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

kob*_*490 181 c# entity-framework entity-framework-6 ef-fluent-api

我正在尝试使用Code First构建一个EF实体,并EntityTypeConfiguration使用流畅的API.使用Unique Constraint创建主键很容易,但不是这样.我看到旧帖子建议为此执行本机SQL命令,但这似乎打败了目的.这可能与EF6有关吗?

Yor*_*rro 267

EF6.2上,您可以使用HasIndex()通过Fluent API添加用于迁移的索引.

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

modelBuilder
    .Entity<User>()
    .HasIndex(u => u.Email)
        .IsUnique();
Run Code Online (Sandbox Code Playgroud)

EF6.1以后,您可以使用IndexAnnotation()在流畅的API中添加迁移索引.

http://msdn.microsoft.com/en-us/data/jj591617.aspx#PropertyIndex

您必须添加以下参考:

using System.Data.Entity.Infrastructure.Annotations;
Run Code Online (Sandbox Code Playgroud)

基本例子

这是一个简单的用法,在User.FirstName属性上添加索引

modelBuilder 
    .Entity<User>() 
    .Property(t => t.FirstName) 
    .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));
Run Code Online (Sandbox Code Playgroud)

实际例子:

这是一个更现实的例子.它在多个属性上添加了唯一索引:User.FirstName并且User.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 }));
Run Code Online (Sandbox Code Playgroud)

  • @AlexanderVasilyev该常量定义为`IndexAnnotation.AnnotationName` (10认同)
  • 将列注释命名为"Index"是必需的!我写了另一个名字,它没用!我花了几个小时才尝试将它重命名为原始的"索引",就像你的帖子一样,并且明白这一点很重要.:(在框架中必须有一个常量,不硬编码字符串. (4认同)
  • @Nathan谢谢!而已!必须使用此常量更正此帖子中的示例. (3认同)
  • 似乎无法在EF7 - DNX中找到它 (2认同)
  • 我相信在第一个示例中创建IndexAttribute时需要将IsUnique设置为true.像这样:`new IndexAttribute(){IsUnique = true}`.否则,它只会创建常规(非唯一)索引. (2认同)

con*_*i2k 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; }
Run Code Online (Sandbox Code Playgroud)

如果数据类型是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; }
Run Code Online (Sandbox Code Playgroud)

如果存在域/存储模型分离问题,使用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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您希望将域模型与存储问题完全分开,则不是这样. (45认同)
  • 您还需要确保引用EntityFramework (4认同)
  • 这仅在您限制字符串长度时才有效,因为SQL不允许将*nvarchar(max)*用作键. (4认同)
  • 如果Index属性与Entity Framework分离,那么我可以将它包含在我的Models项目中.我知道这是一个存储问题,但我使用它的主要原因是对UserNames和Role Names之类的东西设置了唯一的约束. (2认同)
  • 似乎无法在EF7 - DNX中找到它 (2认同)
  • 代码不起作用,我修改它的编辑被拒绝了.这是某种玩笑吗? (2认同)

Bar*_*ann 17

这是一个更流利地设置唯一索引的扩展方法:

public static class MappingExtensions
{
    public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
    {
        return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

modelBuilder 
    .Entity<Person>() 
    .Property(t => t.Name)
    .IsUnique();
Run Code Online (Sandbox Code Playgroud)

将生成迁移,例如:

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" });
    }
}
Run Code Online (Sandbox Code Playgroud)

Src:使用Entity Framework 6.1创建唯一索引流畅的API


Ari*_*oon 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; }
Run Code Online (Sandbox Code Playgroud)


Ken*_*eth 10

不幸的是,实体框架不支持此功能.它是在EF 6的路线图上,但它被推迟了:Workitem 299:独特的约束(唯一索引)