如何在Entity Framework Core模型中使用C# 8.0的可空引用类型?

43

我正在一个.NET Core 3.0项目中启用C# 8.0可空引用类型。该项目使用Entity Framework Core 3.0访问数据库。

以下是一个数据模型,其标题不应为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 CS8618禁用private构造函数的CS8616,但我不认为这是一个好主意。

在这种情况下,应如何使用C# 8.0可空引用类型?或者我的模型是否存在问题或违反最佳实践——如何正确地进行操作?

不幸的是,我没有找到相关的文档或指导。


8
请参考以下网址学习C#中的可空引用类型:https://learn.microsoft.com/zh-cn/ef/core/miscellaneous/nullable-reference-types - Dave Cousineau
3个回答

15

9

我同意你的看法 – pragma 块很不美观。取而代之,我会将 null forgiving 运算符分配给非空引用类型 默认构造函数中,如下所示:

private Vehicle() 
{
    Title = null!;
}

这比内联使用该运算符初始化属性要干净、更具表现力。
public string Title { get; private set; } = null!;

后一种解决方案的意思是:“我知道无论场景如何,Title 都不会为空”,这实际上否定了非空引用类型的好处,因为您将失去所有设计时检查。前一种解决方案的含义是:“我知道在 特定的 场景中,Title 不为空”,因此如果您错过了赋值,编译器将继续在其他地方发出警告。

2
你可能想使用默认关键字而不是null。public string Title { get; private set; } = default!; 这样,你就可以为值类型遵循相同的模式。 - Dave

2
MS Docs for Entity types with constructors中得知:
当EF Core创建这些类型的实例(例如查询结果)时,它将首先调用默认的无参数构造函数,然后将每个属性设置为数据库中的值。但是,如果EF Core找到具有与映射属性相匹配的参数名称和类型的带参数构造函数,则它将使用那些属性的值调用带参数构造函数,而不会显式地设置每个属性。
也许值得创建一个私有构造函数,其中包含这些属性所需的参数,并查看框架是否会调用该函数并正常工作?
此外,除非您完全100%确信可以禁用警告,否则禁用警告不是一个好主意。

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