代码之家  ›  专栏  ›  技术社区  ›  Asaf R

实体框架4中的唯一键

  •  19
  • Asaf R  · 技术社区  · 14 年前

    现有的DB模式具有唯一的、非主的、键和一些依赖于它们的外键。

    是否可以在实体框架v4中定义唯一键(不是主键)?怎么用?

    5 回复  |  直到 14 年前
        1
  •  16
  •   djs Evandro Pomatti    10 年前

    实体框架 六点一 现在支持数据注释和Fluent API的Uniques。

    数据注解 ( Reference )

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

    流畅的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 } 
                            })));
            }
        }
    }
    

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

    此外,为了使用新的索引API,您还必须在项目中安装EntityFramework6.1Nuget包。

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

        2
  •  11
  •   Ken Smith    13 年前

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

        3
  •  10
  •   Mirel Vlad    11 年前

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

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

     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 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; }
    }
    

    接下来,我被要求确保 用户名 '属性将是唯一的。由于没有注释,我不得不想出一个解决办法。这里是:

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

    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命令 它通过在所需列上强制执行唯一索引来更改表--在本例中是用户名。

    可以从主类调用此方法,例如:

    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();
        }
    }
    

    最后一个问题,在尝试运行 程序 课程如下: 表中的列的类型不能用作索引中的键列

    为了解决这个问题,我添加了 [最大长度(250)] 用户名属性的注释。

    下面是用户类的最终外观:

    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
  •  8
  •   Asaf R    13 年前

    我试过定义下表:

    • 订单[ID(主要,标识),客户名称,friendlyordernum(唯一)]
    • orderitems[id(主,标识),friendlyordernum(唯一),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>
    

    没有。也不可能在<EntityType>中添加更多的<key>元素。

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

        5
  •  3
  •   Shimmy Weitzhandler 500 - Internal Server Error    11 年前

    您也可以使用数据注释验证。

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

    您可以从中获取原始代码 here .