用于处理空字符串的数据注释

Data annotations for handling empty strings

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

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

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

[Required(AllowEmptyStrings = true)]

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

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

很简单可能是我没看懂问题:

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

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

这在数据库中和在 C# 等强类型编程语言中是一样的

[DisplayFormat(ConvertEmptyStringToNull = false)]

尝试将此添加到您的 属性

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

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

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

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] (AllowEmptyStrings false or true) 生成此 WHERE 子句:

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

Witout属性不外乎:

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 这样做是为了获得与 C# 中相同的 null 语义。在 SQL 中,当 @__name_0NULL 时,只有 [p].[Name] = @__name_0 未确定,并且查询不会 return 任何记录,甚至 Name 一片空白。 C# 中的相同 LINQ 查询会。第二个 WHERE 子句中的额外空检查说明了 [Name]@__name_0 都为空的情况,这在 C# 中将被视为相等。顺便说一句,如果需要,可以用数据库空语义替换这些空语义。

当需要该字段时,EF 假定该字段值永远不会为 null 并忽略此额外条件。 这种假设会给您带来麻烦。 查询绝不会 return 具有空名称的记录 甚至 显式查询它们时。使用 string name = null; 时,不会 return 编辑具有空名称的记录。

但是现在,对于整个无赖来说,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 中也是如此。

长话短说:不要使用属性。只会害人害己。

备选方案

  • 自己进行这些验证。 This 博客有很多建议。
  • 如果使用 ASP.Net,请使用 DTO/view 具有属性的模型对象来获得早期数据输入验证。不过,这不能替代保存时的所有数据验证。
  • (首选)通过将空字符串转换为有用的内容来修复遗留数据,并使用该属性,因为它(现在是有益的)对查询的影响及其对其他框架中模型验证的影响,如 ASP.Net .