【问题标题】:Does EF Core allow a unique column to contain multiple nulls?EF Core 是否允许唯一列包含多个空值?
【发布时间】:2017-01-03 08:39:04
【问题描述】:

我的实体有一个允许为空的属性。但是,如果它不为空,那么它必须是唯一的。换句话说,该列是唯一的,但允许多个空值。

我试过了:

config.Property(p => p.ProductId).IsRequired(false);

我记得努力让它在 pre-Core EF 中工作。

这可能吗?如何配置实体?

【问题讨论】:

    标签: c# entity-framework ef-code-first entity-framework-core


    【解决方案1】:

    是的,您可以使用 EF Core 执行此操作,因为默认情况下唯一索引创建为过滤索引(WHERE ... IS NOT NULL)

    config.Entity<Product>()
            .HasIndex(b => b.ProductId)
            .IsUnique();
    

    https://github.com/aspnet/EntityFramework/pull/2868

    【讨论】:

    • 我假设这是用于 SQL Server - 你知道 SQLite 是否也支持它吗? “过滤索引”似乎是 MS 的东西?
    • 我在 EF Core 1.0.2 上,这似乎对我不起作用? modelBuilder.Entity("DataModel.Models.Employee", b =>{b.HasIndex("FingerprintId").IsUnique();});仍然收到SqlException: Cannot insert duplicate key row in object 'dbo.Employees' with unique index 'IX_Employees_FingerprintId'. The duplicate key value is (&lt;NULL&gt;).
    • @grokky 您介意分享您正在编写该部分的代码的确切部分吗?一般来说,我对 EF 还是很陌生,我见过多个位置与这个答案的语法相似。
    • @Lawrence 这取决于您如何设计系统。 Erik 的建议绝对有效。我建议您打开一个新问题,显示您的 EF 配置代码。或许 Erik 可以看看,他是 EF 大师之一。
    • 谢谢埃里克。这行得通。
    【解决方案2】:

    我知道这已经过时了,但是对于那些现在发现它的人来说,我在 EF Core 5.0 中看到的默认行为并不是已接受的答案中所描述的。您可以为索引明确指定过滤器,这是我刚刚创建的一个示例:

    modelBuilder.Entity<Reef>(etb =>
                              {
                                  // ...
    
                                  etb.HasIndex(r => r.Label)
                                     .HasFilter("Label IS NOT NULL")
                                     .IsUnique();
    
                                  // ...
                              });
    

    编辑:

    我想我已经得出了完整的答案。如果您有一个可为空值类型的属性,并且您在其上创建了唯一索引,则该索引将默认具有过滤器。但是,如果属性是引用类型,则必须指定它可以为空作为额外的步骤,可以使用 fluent API 或属性。我没有使用属性进行测试,但是使用 fluent API,生成的索引默认情况下不会有过滤器。考虑以下实体:

    public class Thing
    {
        public int ThingId { get; set; }
        public string Text { get; set; }
        public int? StuffId { get; set; }
    
        public Stuff Stuff { get; set; }
    }
    

    在DbContext中添加以下内容:

    modelBuilder.Entity<Thing>(etb =>
                               {
                                   etb.Property(t => t.Text)
                                      .IsRequired(false);
    
                                   etb.HasIndex(t => t.Text)
                                      .IsUnique();
    
                                   etb.HasIndex(t => t.StuffId)
                                      .IsUnique();
                              });
    

    StuffId 列上生成的唯一索引默认有过滤器,而Text 上的唯一索引则没有。必须为Text 列索引显式指定过滤器:

    modelBuilder.Entity<Thing>(etb =>
                               {
                                   etb.Property(t => t.Text)
                                      .IsRequired(false);
    
                                   etb.HasIndex(t => t.Text)
                                      .HasFilter("Text IS NOT NULL")
                                      .IsUnique();
    
                                   etb.HasIndex(t => t.StuffId)
                                      .IsUnique();
                              });
    

    【讨论】:

    • 作为记录,接受的答案是正确的(但对于 EF 5 不完整)。 EF 在索引唯一时创建过滤索引。
    • @GertArnold,我想我已经找出了差异所在。我有一个long? 类型的外键,并且在相应列上生成的唯一索引确实有一个过滤器。上面我的答案中显示的Label 属性是string 类型,因此必须使用etb.Property(r =&gt; r.Label).IsRequired(false) 使其可以为空。该列上生成的唯一索引默认情况下没有过滤器,因此必须明确提供。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 2020-11-16
    • 1970-01-01
    相关资源
    最近更新 更多