【发布时间】:2014-03-01 15:58:33
【问题描述】:
我正在尝试使用 Code First 构建一个 EF 实体,并使用流式 API 构建一个 EntityTypeConfiguration。创建主键很容易,但使用唯一约束并非如此。我看到旧帖子建议为此执行本机 SQL 命令,但这似乎违背了目的。 EF6 可以吗?
【问题讨论】:
标签: c# entity-framework entity-framework-6 ef-fluent-api
我正在尝试使用 Code First 构建一个 EF 实体,并使用流式 API 构建一个 EntityTypeConfiguration。创建主键很容易,但使用唯一约束并非如此。我看到旧帖子建议为此执行本机 SQL 命令,但这似乎违背了目的。 EF6 可以吗?
【问题讨论】:
标签: c# entity-framework entity-framework-6 ef-fluent-api
在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 }));
【讨论】:
IndexAnnotation.AnnotationName
new IndexAttribute() { 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; }
}
}
【讨论】:
这是一个更流畅地设置唯一索引的扩展方法:
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" });
}
}
源:Creating Unique Index with Entity Framework 6.1 fluent API
【讨论】:
@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; }
【讨论】:
很遗憾,实体框架不支持此功能。它在 EF 6 的路线图上,但被推迟了:Workitem 299: Unique Constraints (Unique Indexes)
【讨论】:
modelBuilder.Property(x => x.FirstName).IsUnicode().IsRequired().HasMaxLength(50);
【讨论】: