EF Core 3.0 nullable navigational properties
Asked Answered
A

2

6

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?

Avalokitesvara answered 29/7, 2019 at 9:40 Comment(5)
Did you find a resolution to this? I'm experiencing the same...Woodenhead
@Woodenhead Nope, I'm still #pragma warning disabling all of these :(Avalokitesvara
I'm facing the same issue. Any solution for it now? (of course, expect the workaround...)Cummerbund
I'm digging a grave here but ... .net5 and c# 8, still getting these warnings? Any news on this?Copperas
@Copperas At this point I simply recommend doing #nullable disable before OnModelCreating and #nullable restore after.Avalokitesvara
H
0

As mentioned in the link below, you can use the null-forgiving operator (!) https://learn.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);
Horta answered 11/12, 2021 at 7:24 Comment(0)
C
-1

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 => r.A) property A will be loaded but B will be null.

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

Covington answered 29/7, 2019 at 10:15 Comment(1)
You must mark nullable properties to leverage C# 8 nullable reference types for preventing runtime errors by using compile time type check.Swafford

© 2022 - 2024 — McMap. All rights reserved.