使用流利的API设置唯一约束?


185

我正在尝试使用Code First和EntityTypeConfiguration使用流畅的API 构建EF实体。创建主键很容易,但是使用唯一约束则不容易。我看到的旧文章建议为此执行本机SQL命令,但这似乎无法达到目的。EF6有可能吗?

Answers:


275

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/zh-cn/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
要求将列注释命名为“索引”!我写了另一个名字,但是没有用!在您尝试将其重命名为原始的“索引”之前,我花了数小时的时间,并且明白这一点很重要。:(必须有它的框架没有硬编码常量字符串。
亚历山大·瓦西里耶夫

10
@AlexanderVasilyev常量定义为IndexAnnotation.AnnotationName
Nathan

3
@Nathan谢谢!而已!必须使用此常量更正本文中的示例。
亚历山大·瓦西里耶夫

2
似乎无法在EF7中找到它-DNX
Shimmy Weitzhandler,2015年

2
我相信在第一个示例中创建IndexAttribute时需要将IsUnique设置为true。像这样:new IndexAttribute() { IsUnique = true }。否则,它将创建常规(非唯一)索引。
jakubka's

134

除了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/zh-cn/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; }
    }
}

45
如果您想使域模型与存储问题完全分开,则不可以。
Rickard Liljeberg 2014年

4
您还需要确保引用了EntityFramework
Michael Tranchida 2014年

2
如果Index属性与Entity Framework分开,那就很好了,这样我就可以将其包含在Models项目中。我知道这是一个存储问题,但是我使用它的主要原因是对诸如用户名和角色名之类的东西施加唯一的约束。
山姆

2
似乎无法在EF7中找到它-DNX
Shimmy Weitzhandler,2015年

4
这仅在您还限制字符串的长度时才有效,因为SQL不允许将nvarchar(max)用作键。
JMK

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:使用Entity Framework 6.1 Fluent API创建唯一索引


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


0
modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.