2014-02-05 53 views
156

我想用Code First構建一個EF實體,並且使用流利的API來構建一個EntityTypeConfiguration。創建主鍵很容易,但使用唯一約束並非如此。我看到的舊帖子建議爲此執行原生SQL命令,但這似乎破壞了目的。 EF6有可能嗎?用流暢的API設置唯一約束?

回答

234

EF6.2上,您可以使用HasIndex()爲通過流暢API遷移添加索引。

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

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

EF6.1起,您可以使用IndexAnnotation()您流暢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 })); 
+4

這需要將列註釋命名爲「索引」!我寫了另一個名字,它不起作用!我花了幾個小時才嘗試將它重命名爲原來的「索引」,就像在你的文章中一樣,並且明白這一點很重要。 :( 在框架中必須有一個不固定的代碼字符串。 –

+0

該問題的有用鏈接!http://stackoverflow.com/questions/18889218/unique-key-constraints-for-multiple-columns -in-entity-framework –

+10

@AlexanderVasilyev常量被定義爲'IndexAnnotation.AnnotationName' – Nathan

131

作爲除了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; } 
    } 
} 
+44

如果要使域模型完全分開從存儲問題。 –

+4

您還需要確保您具有對EntityFramework的引用 –

+2

如果Index屬性與Entity Framework分離,那麼可以將其包含在我的Models項目中,這樣會很好。我明白這是一個存儲問題,但我使用它的主要原因是對UserNames和Role Names等東西施加了獨特的限制。 – Sam

16

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

以下是更流暢設置唯一索引擴展方法:

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

的Src: Creating Unique Index with Entity Framework 6.1 fluent API