简体   繁体   中英

EF Core 3.0 nullable navigational properties

So EF Core preview 7 was released and I decided to use it along with C# 8 previews and .NET Core 3.0 preview 7. Let's say I have a class representing a many-to-many relationship:

public class A 
{
    public int Id { get; set; }
    public ICollection<Relation> Relations { get; set; }
}

public class B
{
    public int Id { get; set; }
    public ICollection<Relation> Relations { get; set; }
}

public class Relation
{
    public A A { get; set; }
    public B B { get; set; }

    public int AId { get; set; }
    public int BId { get; set; }
}

I'd map them as this:

modelBuilder.Entity<A>(entity => entity.HasKey(e => e.Id));

modelBuilder.Entity<B>(entity => entity.HasKey(e => e.Id));

modelBuilder.Entity<Relation>(entity =>
{
    entity.HasKey(e => new { e.AId, e.BId });

    entity.HasOne(e => e.A).WithMany(a => a.Relations).HasForeignKey(e => e.AId);

    entity.HasOne(e => e.B).WithMany(b => b.Relations).HasForeignKey(e => e.BId);
});

Now, since I might not want to include one or both of the relation's classes, A and B can be null. Thus, they should be nullable.

var relation = Set<Relations>().Include(r => r.A).First(); // relation.A is not null, but relation.B is null.

So I'd rewrite the class as:

public class Relation
{
    public A? A { get; set; }
    public B? B { get; set; }
}

But now the model building won't work, because these lines:

entity.HasOne(e => e.A).WithMany(a => a.Relations).HasForeignKey(e => e.AId);

entity.HasOne(e => e.B).WithMany(b => b.Relations).HasForeignKey(e => e.BId);

raise CS8602 - Dereference of a possibly null reference on the a.Relations nad b.Relations access, which I set to be treated as errors solution-wide, because it seemed like a sane thing to do.

Note that model building from the other side, so configuring HasMany on A and B , will raise CS8603 - Possible null reference return .

I was able to silently work around the issue by going #pragma warning disable CS8602 but it's obviously a work-around. It looks to me like a smell in EF Core, it'd appear reasonable for this usage to be correct and never raise any issues with null . I was unable to find such an issue on EF Core's github, however.

So the question is, is there a way to have nullable navigational properties without raising a warning on model building in the current EF Core 3.0.0 Preview 7? If not, and this is indeed an issue, is it known and I missed it on EF Core's github or should I raise it there?

As mentioned in the link below, you can use the null-forgiving operator (!) https://docs.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types

so your code must be:

entity.HasOne(e => e.A!).WithMany(a => a.Relations).HasForeignKey(e => e.AId);

entity.HasOne(e => e.B!).WithMany(b => b.Relations).HasForeignKey(e => e.BId);

I have not used .NET Core 3.0 preview 7 but this is how it works on .net Core 2.2 and as far as I can see there have been no changes to this. Navigation property loading is set by default to Explicit loading, so if you do not use .Include() properties A and B will be null. You do not have to set them as nullable. AId and BId will be loaded, by using .Include(r => rA) property A will be loaded but B will be null.

I can't leave a comment so I posted this as an answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM