我有一个名为UserTag的EF Code第一类。
UserTag具有以下两个属性
public string TagText { get; set; }
public UserGroup UserGroup { get; set; }
现在我想要一个索引,使得TagText在UserGroup中是唯一的。但是相同的TagText应该能够存在于两个不同的UserGroup中。
我有两个问题,一个是TagText不能成为varchar(max),第二个是我没有UserGroupId将索引连接到。
我想使用Fluent API,但可以考虑更改我的迁移的上下。
但我不想在TagText上添加UserGroupId和注释。这可能吗?
最好的是Fluent API,但编辑迁移也可以。
答案 0 :(得分:3)
修改强>
我已经错过了你的问题,我会在底部留下原来的答案(我已经过度阅读,你不想在你的模型中添加一个ForeignKey属性)。
使用流畅的API可以做到这一点。
基本上你必须配置EF如何将导航属性(UserGroup)映射到数据库(外键列的名称,模型中不存在)并放置索引属性/注释就可以了。
为了解决TagText列长度的问题(默认情况下是 nvarchar(max),因此不能成为索引的一部分(太长了,你会得到一个SQL异常) ),您还可以使用流畅的API并使用 .HasMaxLength(StringLengthThatMakesSense)。这也可以通过在模型中添加注释来完成(请参阅下面的旧答案)。
modelBuilder.Entity<UserTag>()
.HasRequired(x => x.UserGroup)
.WithMany() // I assume a 1 : many relation
.Map(x =>
// map the Foreignkey to the default naming convention
x.MapKey("UserGroup_Id")
// add a Columnanotation, which you would place on the FK property, if you had one...
.HasColumnAnnotation("UserGroup_Id", "Index", new IndexAnnotation(new IndexAttribute("UI_UserGroupTagtext", 2)
{
IsUnique = true
})));
modelBuilder.Entity<UserTag>()
.Property(x => x.TagText)
// configure the length of the column in the database
.HasMaxLength(128)
// add the Unique index information - I used this column to be the first in the index
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UI_UserGroupTagtext", 1)
{
IsUnique = true
}));
这应该会为您提供如下所示的迁移:
CreateTable(
"dbo.UserTags",
c => new
{
Id = c.Int(nullable: false, identity: true),
TagText = c.String(maxLength: 128),
UserGroup_Id = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.UserGroups", t => t.UserGroup_Id, cascadeDelete: true)
.Index(t => new { t.TagText, t.UserGroup_Id }, unique: true, name: "UI_UserGroupTagtext");
CreateTable(
"dbo.UserGroups",
c => new
{
Id = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.Id);
您的问题有多种解决方案。
正如您已经提到的,您始终可以在数据库迁移中执行此操作,只需使用两列创建唯一索引(我猜关系模型包含UserGroupId)。
要通过数据注释创建唯一索引,您需要像这样扩展模型(需要EF 6.1 ):
public class UserTag {
[StringLength(128)]
[Required]
[Index("UI_UserGroupTagtext", 2, IsUnique = true)]
public string TagText { get; set; }
[Index("UI_UserGroupTagtext", 1, IsUnique = true)]
public int UserGroupId { get; set; }
public UserGroup UserGroup { get; set; }
}
我公开了ForeignKey属性(信息:我不是100%确定是否需要这个,也许它直接放在navigationproperty上时也有效)。这适用于约定(通过命名FK属性作为带有Id后缀的navigationproeprty。我假设用户组的Id是一个整数)。您可以在msdn上阅读有关此约定的更多信息(请参阅答案底部的链接)
我还添加了 StringLength 属性,因为否则EF通常会创建一个 NVARCHAR(MAX)列,这在SQL Server中不起作用,因为它超过了最大值。索引长度(正如您在答案中已提到的那样)。这也将使EF在调用SaveChanges时验证属性的长度,而无需进入数据库(但可以禁用)。
另一种选择是通过 Fluent Api :
执行此操作modelBuilder.Entity<UserTag>
.Property(t => t.TagText )
.HasMaxLength(128)
.IsRequired()
.HasUniqueIndexAnnotation("UI_UserGroupTagtext", 2);
modelBuilder.Entity<UserTag>
.Property(t => t.UserGroupId)
.HasUniqueIndexAnnotation("UI_UserGroupTagtext", 1);
在这个例子中,我还添加了TagText的MaxLength信息(以及一个必需的信息,因为这似乎至少对我有意义......)。
您可以阅读有关EF和索引on msdn
的更多信息