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

问题描述 投票:0回答:6

我正在尝试使用 Code First 构建一个 EF 实体,并使用 Fluent API 构建一个

EntityTypeConfiguration
。创建主键很容易,但使用唯一约束则不然。我看到旧的帖子建议为此执行本机 SQL 命令,但这似乎达不到目的。 EF6 可以吗?

c# entity-framework entity-framework-6 ef-fluent-api
6个回答
300
投票

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

137
投票

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

19
投票

这里有一个更流畅设置唯一索引的扩展方法:

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

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


17
投票

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

11
投票

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


-1
投票
modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);
© www.soinside.com 2019 - 2024. All rights reserved.