用流畅的 API 设置唯一的约束?

我试图用代码优先构建一个 EF 实体,用流畅的 API 构建一个 EntityTypeConfiguration。创建主键很容易,但是使用惟一约束就不那么容易了。我看到过一些旧文章建议为此执行本地 SQL 命令,但这似乎违背了其目的。EF6有可能做到这一点吗?

113163 次浏览

遗憾的是,实体框架不支持这一点。它在 EF6的路线图上,但它被推迟了: 工作项299: 唯一约束(唯一索引)

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

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

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

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

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: 使用实体框架6.1流畅的 API 创建惟一索引

modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);