EF Core 3.0可空导航属性

6

EF Core Preview 7已经发布,我决定和C# 8预览版以及.NET Core 3.0预览版一起使用。假设我有一个表示多对多关系的类:

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; }
}

我会将它们映射为这样:

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);
});

现在,由于我可能不想包括关系中的AB类之一或两者,因此它们可以为null。因此,它们应该是可空的。

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

所以,我会将这个类重写为:

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

但现在模型构建将不起作用,因为以下这些行:
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);

在全局范围内,我将a.Relationsb.Relations的访问设置为转换为错误,因为这似乎是一件明智的事情,会引发CS8602-可能为空引用的解除引用异常。请注意,从另一侧构建模型时,因此在AB上配置HasMany,将引发CS8603-可能为空引用返回异常。我能够通过使用#pragma warning disable CS8602来默默地解决问题,但这显然是一个权宜之计。对于这种使用情况来说,EF Core中的这种现象看起来像是一个“bad smell”,似乎合理且不会引发任何与null有关的问题。然而,我在EF Core的github上没有找到这样的问题。因此,问题是,在当前的EF Core 3.0.0预览版7中,是否有一种方式可以具有可空导航属性而不在模型构建时引发警告?如果没有,则这确实是一个问题,我是否在EF Core的github上错过了这个问题,或者应该在那里提出问题?

3
你解决了这个问题吗?我也遇到了同样的情况。 - DrGriff
@DrGriff 不,我仍然在禁用所有这些 #pragma warning :( - V0ldek
我遇到了相同的问题,现在有解决方案了吗?(当然,除了绕过这个问题的方法...) - Cheesi
我在这里挖掘一个坟墓,但是......使用 .net5 和 c#8,仍然收到这些警告?有任何新消息吗? - nilsK
@nilsK 在这一点上,我建议在 OnModelCreating 之前执行 #nullable disable,并在之后执行 #nullable restore - V0ldek
2个回答

0

-1

我没有使用过 .NET Core 3.0 预览版 7,但这是在 .NET Core 2.2 上的工作方式,据我所知,此方面没有任何更改。导航属性加载默认设置为显式加载,因此如果您不使用 .Include() 属性,则 A 和 B 属性将为 null。您不需要将它们设置为可空的。通过使用 .Include(r => r.A) 属性,将加载 AIdBId,A 属性将被加载,但 B 属性将为 null。

我不能留下评论,所以我把它作为答案发表了。


你必须标记可空属性,以利用C# 8的可空引用类型,通过编译时类型检查来防止运行时错误。 - Mikhail Zhuravlev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接