【问题标题】:How to use C# 8.0 Nullable Reference Types with Entity Framework Core models?如何将 C# 8.0 可空引用类型与 Entity Framework Core 模型一起使用?
【发布时间】:2020-01-29 23:41:52
【问题描述】:

我在 .NET Core 3.0 项目上启用 C# 8.0 Nullable Reference Types。项目使用Entity Framework Core 3.0访问数据库。

下面是一个Title不能为null的数据模型。

public class Vehicle
{
    public int Id { get; private set; } 

    public string Title { get; private set; }

    // Entity Framework Core is instructed to bind to the private _drivers field in a configuration builder
    private readonly List<Driver> _drivers = new List<Driver>();
    public IReadOnlyCollection<Driver> Drivers => _drivers.AsReadOnly();

    private Vehicle() 
    {
    }

    public Vehicle(string title) 
    {
        this.Title = title;
    }

    public void AddDriver(string name)
    {
         this._drivers.Add(new Driver(name));
    }
 }

// A foreign column is defined in a configuration builder
public class Driver
{
    public int Id { get; private set; } 

    public string Name { get; private set; }

    private Driver() 
    {
    }

    public Driver(string name) 
    {
        this.Name = name;
    }
 }

自己的代码应该只使用 public 构造函数,而 private 构造函数只是为了允许 Entity Framework Core 和(可能还有)序列化将值从数据库绑定到这些类/模型。公共构造函数可能具有与模型具有的属性不同的结构、列表和参数类型(例如,它可能还包含第一个必需子项的参数,它可能具有一些可选参数等)。

但是,编译器会在 private 构造函数上生成 CS8618 Non-nullable field is uninitialized. Consider declaring as nullable.

我可以通过 #pragma warning disable CS8618private 构造函数禁用 CS8616,但我认为这不是一个好主意。

在这种情况下应该如何使用 C# 8.0 可空引用类型? 还是我的模型是伪造的或违反了最佳实践 - 如何正确执行?

很遗憾,我没有找到相关的文档或指南。

【问题讨论】:

标签: c# entity-framework .net-core entity-framework-core nullable-reference-types


【解决方案1】:

没有适当的方法来处理不可为空的导航属性。

  1. 文档提出了两种方法,但都不是类型安全的。用一个 支持字段并抛出 InvalidOperationException。不清楚如何 它不同于什么都不做并且有一个 NullReferenceException
  2. 使用 null 宽恕运算符抑制它

官方文档链接:https://docs.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types#non-nullable-properties-and-initialization

【讨论】:

    【解决方案2】:

    我同意你的看法——pragma 块很难看。相反,我会将 null 宽恕运算符分配给默认构造函数 inside 的不可为 null 的引用类型,如下所示:

    private Vehicle() 
    {
        Title = null!;
    }
    

    这比使用上述操作符内联初始化属性更简洁,更具表现力,如下所示:

    public string Title { get; private set; } = null!;
    

    后一种解决方案读作“我知道Title 在任何情况下都不为空”,这实际上否定了不可为空引用类型的好处,因为您丢失了所有设计时检查。前者读作“我知道Title此特定 场景中不为空”,因此如果您错过分配,编译器警告会继续在其他地方发出。

    【讨论】:

    • 您可能希望使用 default 关键字而不是 null。 public string Title { get; private set; } = default!;。这样,您可以对值类型遵循相同的模式。
    【解决方案3】:

    来自MS Docs for Entity types with constructors

    当 EF Core 创建这些类型的实例时,例如为结果 的查询,它会首先调用默认的无参数构造函数 然后将每个属性设置为数据库中的值。然而,如果 EF Core 找到一个带有参数名称的参数化构造函数,并且 匹配映射属性的类型,然后它将改为调用 具有这些属性的值的参数化构造函数和 不会显式设置每个属性。

    也许值得创建一个带有这些属性所需参数的私有 ctor,然后看看框架是否会调用它并工作?

    除非您完全 100% 确信可以禁用警告,否则禁用警告也不是一个好主意。

    【讨论】:

      猜你喜欢
      • 2016-03-28
      • 1970-01-01
      • 1970-01-01
      • 2017-11-18
      • 1970-01-01
      • 2017-10-19
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多