【问题标题】:Setting unique Constraint with fluent API?使用流畅的 API 设置唯一约束?
【发布时间】:2014-03-01 15:58:33
【问题描述】:

我正在尝试使用 Code First 构建一个 EF 实体,并使用流式 API 构建一个 EntityTypeConfiguration。创建主键很容易,但使用唯一约束并非如此。我看到旧帖子建议为此执行本机 SQL 命令,但这似乎违背了目的。 EF6 可以吗?

【问题讨论】:

    标签: c# entity-framework entity-framework-6 ef-fluent-api


    【解决方案1】:

    EF6.2上,您可以使用HasIndex()添加索引,以便通过fluent API进行迁移。

    https://github.com/aspnet/EntityFramework6/issues/274

    示例

    modelBuilder
        .Entity<User>()
        .HasIndex(u => u.Email)
            .IsUnique();
    

    EF6.1 开始,您可以使用 IndexAnnotation() 在 fluent API 中添加迁移索引。

    http://msdn.microsoft.com/en-us/data/jj591617.aspx#PropertyIndex

    您必须添加参考:

    using System.Data.Entity.Infrastructure.Annotations;
    

    基本示例

    这里是一个简单的用法,在User.FirstName属性上添加索引

    modelBuilder 
        .Entity<User>() 
        .Property(t => t.FirstName) 
        .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
    

    实例:

    这是一个更现实的例子。它为多个属性添加了唯一索引User.FirstNameUser.LastName,索引名称为“IX_FirstNameLastName”

    modelBuilder 
        .Entity<User>() 
        .Property(t => t.FirstName) 
        .IsRequired()
        .HasMaxLength(60)
        .HasColumnAnnotation(
            IndexAnnotation.AnnotationName, 
            new IndexAnnotation(
                new IndexAttribute("IX_FirstNameLastName", 1) { IsUnique = true }));
    
    modelBuilder 
        .Entity<User>() 
        .Property(t => t.LastName) 
        .IsRequired()
        .HasMaxLength(60)
        .HasColumnAnnotation(
            IndexAnnotation.AnnotationName, 
            new IndexAnnotation(
                new IndexAttribute("IX_FirstNameLastName", 2) { IsUnique = true }));
    

    【讨论】:

    • 这是将列注释命名为“索引”所必需的!我写了另一个名字,它没有用!我花了几个小时才尝试将其重命名为原始“索引”,如您的帖子中所示,并了解这很重要。 :( 框架中必须有一个常量才能不对字符串进行硬编码。
    • @AlexanderVasilyev 常量定义为IndexAnnotation.AnnotationName
    • @Nathan 谢谢!而已!这篇文章中的例子必须使用这个常量来修正。
    • 在 EF7 - DNX 中似乎找不到它
    • 我相信在第一个例子中创建IndexAttribute时需要将IsUnique设置为true。像这样:new IndexAttribute() { IsUnique = true }。否则它只会创建常规(非唯一)索引。
    【解决方案2】:

    作为对 Yorro 回答的补充,也可以通过使用属性来完成。

    int 类型唯一组合键的示例:

    [Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
    public int UniqueKeyIntPart1 { get; set; }
    
    [Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
    public int UniqueKeyIntPart2 { get; set; }
    

    如果数据类型为string,则必须添加MaxLength属性:

    [Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
    [MaxLength(50)]
    public string UniqueKeyStringPart1 { get; set; }
    
    [Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
    [MaxLength(50)]
    public string UniqueKeyStringPart2 { get; set; }
    

    如果存在域/存储模型分离问题,可以选择使用Metadatatype 属性/类:https://msdn.microsoft.com/en-us/library/ff664465%28v=pandp.50%29.aspx?f=255&MSPPError=-2147217396


    快速控制台应用示例:

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity;
    
    namespace EFIndexTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (var context = new AppDbContext())
                {
                    var newUser = new User { UniqueKeyIntPart1 = 1, UniqueKeyIntPart2 = 1, UniqueKeyStringPart1 = "A", UniqueKeyStringPart2 = "A" };
                    context.UserSet.Add(newUser);
                    context.SaveChanges();
                }
            }
        }
    
        [MetadataType(typeof(UserMetadata))]
        public class User
        {
            public int Id { get; set; }
            public int UniqueKeyIntPart1 { get; set; }
            public int UniqueKeyIntPart2 { get; set; }
            public string UniqueKeyStringPart1 { get; set; }
            public string UniqueKeyStringPart2 { get; set; }
        }
    
        public class UserMetadata
        {
            [Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
            public int UniqueKeyIntPart1 { get; set; }
    
            [Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
            public int UniqueKeyIntPart2 { get; set; }
    
            [Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
            [MaxLength(50)]
            public string UniqueKeyStringPart1 { get; set; }
    
            [Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
            [MaxLength(50)]
            public string UniqueKeyStringPart2 { get; set; }
        }
    
        public class AppDbContext : DbContext
        {
            public virtual DbSet<User> UserSet { get; set; }
        }
    }
    

    【讨论】:

    • 如果您想让您的域模型与存储问题完全分离,则不是。
    • 您还需要确保您有对 EntityFramework 的引用
    • 如果 Index 属性从实体框架中分离出来就好了,这样我就可以将它包含在我的模型项目中。我知道这是一个存储问题,但我使用它的主要原因是对 UserNames 和 Role Names 等内容设置独特的约束。
    • 在 EF7 - DNX 中似乎找不到它
    • 这仅在您还限制字符串长度时才有效,因为 SQL 不允许将 nvarchar(max) 用作键。
    【解决方案3】:

    这是一个更流畅地设置唯一索引的扩展方法:

    public static class MappingExtensions
    {
        public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
        {
            return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
        }
    }
    

    用法:

    modelBuilder 
        .Entity<Person>() 
        .Property(t => t.Name)
        .IsUnique();
    

    会产生迁移如:

    public partial class Add_unique_index : DbMigration
    {
        public override void Up()
        {
            CreateIndex("dbo.Person", "Name", unique: true);
        }
    
        public override void Down()
        {
            DropIndex("dbo.Person", new[] { "Name" });
        }
    }
    

    源:Creating Unique Index with Entity Framework 6.1 fluent API

    【讨论】:

      【解决方案4】:

      @coni2k 的答案是正确的,但是您必须添加 [StringLength] 属性才能使其正常工作,否则您将获得无效的密钥异常(示例如下)。

      [StringLength(65)]
      [Index("IX_FirstNameLastName", 1, IsUnique = true)]
      public string FirstName { get; set; }
      
      [StringLength(65)]
      [Index("IX_FirstNameLastName", 2, IsUnique = true)]
      public string LastName { get; set; }
      

      【讨论】:

        【解决方案5】:

        很遗憾,实体框架不支持此功能。它在 EF 6 的路线图上,但被推迟了:Workitem 299: Unique Constraints (Unique Indexes)

        【讨论】:

          【解决方案6】:
          modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-04-10
            • 1970-01-01
            • 2015-09-12
            • 2014-11-18
            • 2013-04-30
            • 1970-01-01
            • 1970-01-01
            • 2016-07-12
            相关资源
            最近更新 更多