Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework - Why do I get optional dependent using table sharing?

I am getting the following warning:

Microsoft.EntityFrameworkCore.Update: Warning: The entity of type 'Event.Description#RichText' is an optional dependent using table sharing. The entity does not have any property with a non-null value to identify whether the entity exists. This means that when it is queried no object instance will be created instead of an instance with all properties set to null values. Any nested dependents will also be lost. Either don't save any instance with only null values or mark the incoming navigation as required in the model. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the key values of the entity.

This is declared as:

public class Event
{
    public RichText? Description { get; set; }
}

and

public class RichText
{
    public string OpenXmlFilename { get; private set; }
    public string HtmlFilename { get; private set; }
    public string HtmlBody { get; private set; }
    public string Text { get; private set; }
    public RichText()
    {
        OpenXmlFilename = HtmlFilename = Text = HtmlBody = string.Empty;
    }
}

What I don't understand is the warnings around this say I can't save a Description property where all of its properties are null. But I can't do that anyways as all of them are declared to not be null.

So why the warning? And is there an issue if I will never instantiate a RichText object with all null properties?


Update: Here's the config command:

public class EventConfiguration : IEntityTypeConfiguration<Event>
{
    public void Configure(EntityTypeBuilder<Event> builder)
    {
        builder.OwnsOne(u => u.Description, desc =>
        {
            desc.Property(a => a.OpenXmlFilename).IsRequired();
        });
    }
}

As requested below, here's a part from TrackingDbContextModelSnapshot.cs

modelBuilder.Entity("LouisHowe.core.Models.Event", b =>
    {
        b.OwnsOne("LouisHowe.core.Models.RichText", "Description", b1 =>
            {
                b1.Property<int>("EventId")
                    .HasColumnType("int");

                b1.Property<string>("HtmlBody")
                    .IsRequired()
                    .HasColumnType("nvarchar(max)");

                b1.Property<string>("HtmlFilename")
                    .IsRequired()
                    .HasColumnType("nvarchar(max)");

                b1.Property<string>("OpenXmlFilename")
                    .IsRequired()
                    .HasColumnType("nvarchar(max)");

                b1.Property<string>("Text")
                    .IsRequired()
                    .HasColumnType("nvarchar(max)");

                b1.HasKey("EventId");

                b1.ToTable("Events");

                b1.WithOwner()
                    .HasForeignKey("EventId");
            });
like image 558
David Thielen Avatar asked Dec 28 '25 06:12

David Thielen


2 Answers

I found what is causing this and put this in the category of very badly written error messages.

I had a bug in my code where, on an update, Event.Description was created with all null properties. All the properties are declared as non-null but that is not enforced. (As I said, a bug.)

So it then goes to update the record and EF is given a value that will write the Event.Description columns, but with nulls so on the next read Event.Description will be viewed as null.

Definitely a problem and EF is good to call it out. Once I understood the issue then the warning made sense. But before I knew what was going on, I read it as it could not figure out if Event.Description was null if saved with non-null values.

like image 97
David Thielen Avatar answered Dec 30 '25 18:12

David Thielen


While instantiating object Event, EF Core is trying to understand when assign Description to null and when create RichText with all properties. When all properties are nullable it сan't make a clear decision for that.

Schematically (just for explaining) EF Core will create the following mapper from DbDataReader for querying Event:

(DbDataReader r) => new Event
{
    Description = new RichText
    {
        OpenXmlFilename = r.IsDBNull(0) ? null : r.GetString(0),
        HtmlFilename = r.IsDBNull(1) ? null : r.GetString(1),
        HtmlBody = r.IsDBNull(2) ? null : r.GetString(2),
        Text = r.IsDBNull(3) ? null : r.GetString(3)
    }
};

So Description is not null, but all properties are null.

Having at least one not nullable field will help EF Core to make a decision.

(DbDataReader r) => new Event
{
    Description = r.IsDBNull(4) ? null 
        : new RichText
        {
            OpenXmlFilename = r.IsDBNull(0) ? null : r.GetString(0),
            HtmlFilename = r.IsDBNull(1) ? null : r.GetString(1),
            HtmlBody = r.IsDBNull(2) ? null : r.GetString(2),
            Text = r.IsDBNull(3) ? null : r.GetString(3),
            NotNullableField = r.GetString(4)
        }
};
like image 44
Svyatoslav Danyliv Avatar answered Dec 30 '25 19:12

Svyatoslav Danyliv