3

我使用 EF Core Powertools 将我的 Db 中的一组表逆向工程为 EF 数据模型。

在表中创建记录时,一个或多个 varchar 字段被标记为允许为空。

如果我更新这些字段上的实体属性以使用

[Required(AllowEmptyStrings = true)]

这将使空字符串通过,但是在查询表中已经包含一个或多个这些字段的空值的实体列表时,这不会因为属性而失败吗?例如,它不只是空的,它是空的。

那么如何修改实体定义以既允许保存空字符串,又允许查询结果中的空值呢?

4

3 回答 3

6

tl;dr
该属性不能帮助您进行数据验证。它甚至会给您带来麻烦,因为它限制了您的查询选项。

首先,与 EF6 不同,EF 核心不进行任何数据验证。因此,任何属性都无法满足您阻止空字符串进入可为空的数据库字段的良好意图。

更糟糕的是,该属性会给你带来麻烦。SQL 查询生成受是否需要属性的影响。让我演示一下使用这个小类:

public class Product
{   
    public int ID { get; set; }

    [Required(AllowEmptyStrings = true)] // or false
    public string Name { get; set; }
}

这个查询...

string name = "a";
var products = db.Products
    .Where(x => x.Name == name)
    .ToList();

...with [Required]AllowEmptyStringsfalse 或 true)生成此WHERE子句:

WHERE ([p].[Name] = @__name_0) AND @__name_0 IS NOT NULL

没有属性不外乎

WHERE (([p].[Name] = @__name_0) AND ([p].[Name] IS NOT NULL AND @__name_0 IS NOT NULL))
    OR ([p].[Name] IS NULL AND @__name_0 IS NULL)

EF 这样做是为了获得与nullC# 中相同的语义。在 SQL 中,只是[p].[Name] = @__name_0不确定何时@__name_0NULL并且查询不会返回任何记录,即使Name是 null 的记录也不返回。C# 中的相同 LINQ 查询会。第二WHERE个子句中额外的空检查说明了两者都为空的情况[Name]@__name_0这在 C# 中将被视为相等。顺便说一句,如果需要,这些空语义可以用数据库空语义代替。

当需要该字段时,EF 假定该字段值永远不会为空,并省略此额外条件。这个假设是给你带来麻烦的原因。即使显式查询它们,查询也永远不会返回具有空名称的记录。没有带有string name = null;空名称的记录将被返回。

但是现在对于总的无赖,EF 甚至不允许您null通过附加条件显式查询值:

var products = db.Products
    .Where(x => x.Name == name || x.Name == null)
    .ToList();

EF 只是忽略了这个name == null条件。可以确定该字段不能包含此查询的空值...

var products = db.Products
    .Where(x => x.Name == null)
    .ToList();

产生这个 SQL 谓词:

WHERE CAST(0 AS bit) = CAST(1 AS bit)

打扰一下?请问我可以查询空值吗?你在那里,背负着一个遗留数据库,试图通过从现在开始制作必填字段来尽你所能,但 EF 使它几乎不可能。在 EF6 中也是如此。

长话短说:不要使用该属性。它只会有害无益。

备择方案

  • 自己进行这些验证。这个博客有一些建议。
  • 如果使用 ASP.Net,请使用具有属性的 DTO/视图模型对象来获得早期数据输入验证。但是,这不能代替保存时的所有数据验证。
  • (首选)通过将空字符串转换为有用的东西来修复遗留数据并使用该属性,因为它(现在是有益的)对查询的影响以及它对其他框架(如 ASP.Net)中的模型验证的影响。
于 2019-11-24T08:57:32.900 回答
1

这很简单,也许我不明白这个问题:

  • 离开[Required]属性将允许空值和任何字符串,也允许空字符串
  • 离开[Required]属性并将[MinLength()]属性设置为某个大于 0 的值将允许空值和字符串,但不允许
  • 设置[Required]属性将不允许空值,但允许空字符串。
  • [Required(AllowEmptyStrings = true)]也是如此。
  • _[Required(AllowEmptyStrings = false)] 可以看作是[Required, MinLength(1)]的快捷方式

从技术上讲,null 甚至没有类型。Null 不是 string 没有 int 没有任何东西,它只是 null。空字符串是一个恰好没有字母的有效字符串。

这在数据库中与在 C# 等强类型编程语言中相同

于 2019-11-21T20:58:52.190 回答
-1
[DisplayFormat(ConvertEmptyStringToNull = false)]

尝试将此添加到您的资源中

于 2019-11-21T21:15:22.607 回答