【问题标题】:Unique keys in Entity Framework 4Entity Framework 4 中的唯一键
【发布时间】:2010-04-10 20:55:32
【问题描述】:

现有的数据库架构具有唯一的非主键和一些依赖它们的外键。

是否可以在 Entity Framework v4 中定义不是主键的唯一键?怎么样?

【问题讨论】:

    标签: entity-framework entity-framework-4 unique-key


    【解决方案1】:

    实体框架 6.1 现在支持具有数据注释和 Fluent API 的唯一性。

    数据注释 (Reference)

    public class MyEntityClass
    { 
        [Index(IsUnique = true)]
        [MaxLength(255)] // for code-first implementations
        public string MyUniqueProperty{ get; set; } 
    }
    

    Fluent API (Reference)

    public class MyContext : DbContext
        {
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder 
                    .Entity<MyEntityClass>() 
                    .Property(t => t.MyUniqueProperty) 
                    .HasMaxLength(255) // for code-first implementations
                    .HasColumnAnnotation( 
                        "Index",  
                        new IndexAnnotation(new[] 
                            { 
                                new IndexAttribute("Index") { IsUnique = true } 
                            })));
            }
        }
    }
    

    您必须应用索引并将唯一属性设置为 true。默认情况下,根据文档,索引是非唯一的。

    您还必须在项目中安装 Entity Framework 6.1 NuGet 包才能使用新的索引 API。

    关于代码优先实现的注意事项:VARCHAR(MAX) 不能成为唯一约束的一部分。您必须将最大长度指定为数据注释或在 Fluent API 中。

    【讨论】:

    • 这为我编译,但我得到一个运行时错误,Column 'Email' in table 'dbo.Users' is of a type that is invalid for use as a key column in an index. Email 是一个公共字符串,就像 MyUniqueProperty 一样。
    • 这里工作正常,我做了很多尝试来重现你的错误,但我没能做到。您会打开一个新问题,提供所有涉及的详细信息,包括 EF 版本和完整的堆栈跟踪以及您的课程吗?请在此处添加带有链接的评论,以便我进行调查。发送!
    • 我的问题是因为我使用的是代码优先实现,默认情况下将Email 列创建为NVARCHAR(MAX)。我做了一个编辑来解决这个案例。你的解决方案现在对我来说很好!
    • @djs 这很奇怪。我在这里使用 SQL Compact 和 CF 也使用 drop-create 策略,我没有收到任何错误。也许它与数据库有关? Tx 用于更新。
    • 我使用的是 SQL Server 2014。这可能会有所不同。
    【解决方案2】:

    另请参阅此 MSDN 博客文章:http://blogs.msdn.com/b/efdesign/archive/2011/03/09/unique-constraints-in-the-entity-framework.aspx。简而言之,这在 V4 中不受支持,尽管 EF 团队似乎计划在未来的版本中支持它。

    【讨论】:

    • 感谢链接,这正是我想要的。
    • 很遗憾,未来的版本不会是下一个版本(EF 5.0 和 .NET 4.5)
    【解决方案3】:

    不久前我遇到了同样的问题。

    我得到了一个包含几个表的数据库(见下文)。

     public class ClinicDbContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Doctor> Doctors { get; set; }
        public DbSet<Patient> Patients { get; set; }
        public DbSet<Secretary> Secretarys { get; set; }
        public DbSet<Disease> Diseases { get; set; }
        public DbSet<Consultation> Consultations { get; set; }
        public DbSet<Administrator> Administrators { get; set; }
    }
    

    Users 表是这样描述的:

    public class User
    {
        [Key]
        public Guid UserId { get; set; }
    
        public string UserName { get; set; }
    
        public string Password { get; set; }
    
        public string Name { get; set; }
        public string Surname { get; set; }
        public string IdentityCardNumber { get; set; }
        public string PersonalNumericalCode { get; set; }
        public DateTime DateOfBirth { get; set; }
        public string Address { get; set; }
    }
    

    接下来,我被要求确保所有 'UserName' 属性都是唯一的。由于没有注释,我不得不想出一个解决方法。这里是:

    首先,我将我的数据库上下文类更改为如下所示:

    public class ClinicDbContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Doctor> Doctors { get; set; }
        public DbSet<Patient> Patients { get; set; }
        public DbSet<Secretary> Secretarys { get; set; }
        public DbSet<Disease> Diseases { get; set; }
        public DbSet<Consultation> Consultations { get; set; }
        public DbSet<Administrator> Administrators { get; set; }
    
        public class Initializer : IDatabaseInitializer<ClinicDbContext>
        {
            public void InitializeDatabase(ClinicDbContext context)
            {
                if (!context.Database.Exists() || !context.Database.CompatibleWithModel(false))
                {
                    if (context.Database.Exists())
                    {
                        context.Database.Delete();
                    }
                    context.Database.Create();
    
                    context.Database.ExecuteSqlCommand("CREATE INDEX IX_Users_UserName ON dbo.Users ( UserName )");
                }
            }
        }
    }
    

    上面的重要部分是 sql 命令,它通过在我们想要的列上强制执行唯一索引来更改表 - 在我们的例子中是 UserName。

    这个方法可以从主类中调用,例如:

    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer<ClinicDbContext>(new ClinicDbContext.Initializer());
    
            using (var ctx = new ClinicDbContext())
            {
                Console.WriteLine("{0} products exist in the database.", ctx.Users.Count());
            }
    
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
    

    在尝试运行 Program 类时发生的最后一个问题如下:表中的列的类型为不能用作索引中的键列

    为了解决这个问题,我刚刚为 UserName 属性添加了一个 [MaxLength(250)] 注释。

    下面是 User 类最终的样子:

    public class User
    {
        [Key]
        public Guid UserId { get; set; }
    
        [MaxLength(250)]
        public string UserName { get; set; }
    
        public string Password { get; set; }
    
        public string Name { get; set; }
        public string Surname { get; set; }
        public string IdentityCardNumber { get; set; }
        public string PersonalNumericalCode { get; set; }
        public DateTime DateOfBirth { get; set; }
        public string Address { get; set; }
    }
    

    希望它也能解决你的问题!

    【讨论】:

      【解决方案4】:

      我尝试定义以下表格:

      • 订单 [Id (primary, identity), ClientName, FriendlyOrderNum (unique)]
      • OrderItems [Id (primary, identity), FriendlyOrderNum (unique), ItemName]

      还有一个从 OrderItems.FriendlyOrderNum (Mant) 到 Orders.FriendlyOrderNum (one) 的外键映射。

      如果唯一的非主键是可能的,那么下面的 SSDL 应该可以工作:

      <Schema Namespace="EfUkFk_DbModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
          <EntityContainer Name="EfUkFk_DbModelStoreContainer">
            <EntitySet Name="OrderItems" EntityType="EfUkFk_DbModel.Store.OrderItems" store:Type="Tables" Schema="dbo" />
            <EntitySet Name="Orders" EntityType="EfUkFk_DbModel.Store.Orders" store:Type="Tables" Schema="dbo" />
          </EntityContainer>
          <EntityType Name="OrderItems">
            <Key>
              <PropertyRef Name="RowId" />
            </Key>
            <Property Name="RowId" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" />
            <Property Name="OrderNum" Type="char" Nullable="false" MaxLength="5" />
            <Property Name="ItemName" Type="varchar" MaxLength="100" />
          </EntityType>
          <!--Errors Found During Generation:
        warning 6035: The relationship 'FK_OrderItems_Orders' has columns that are not part of the key of the table on the primary side of the relationship. The relationship was excluded.
        -->
          <EntityType Name="Orders">
            <Key>
              <PropertyRef Name="RowId" />
            </Key>
            <Property Name="RowId" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" />
            <Property Name="ClientName" Type="varchar" MaxLength="100" />
            <Property Name="OrderNum" Type="char" Nullable="false" MaxLength="5" />
          </EntityType>
      
        <!-- AsafR -->
          <Association Name="FK_OrderItems_Orders">
            <End Role="Orders" Type="EfUkFk_DbModel.Store.Orders" Multiplicity="1">
            </End>
            <End Role="OrderItems" Type="EfUkFk_DbModel.Store.OrderItems" Multiplicity="*" />
            <ReferentialConstraint>
              <Principal Role="Orders">
                <PropertyRef Name="OrderNum" />
              </Principal>
              <Dependent Role="OrderItems">
                <PropertyRef Name="OrderNum" />
              </Dependent>
            </ReferentialConstraint>
          </Association>
        </Schema></edmx:StorageModels>
      

      它没有。也不可能在 中添加更多 元素。

      我的结论是 EF 4 不支持非主唯一键。

      【讨论】:

        【解决方案5】:

        您也可以使用 DataAnnotations 验证。

        我创建了this (UniqueAttribute) 类,它继承ValidationAttribute,当应用于属性时,将在验证期间检索和验证该列的值。

        您可以从here 获取原始代码。

        【讨论】:

          猜你喜欢
          • 2011-02-11
          • 2016-07-12
          • 1970-01-01
          • 2019-04-19
          • 1970-01-01
          • 1970-01-01
          • 2011-01-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多