EF 代码优先索引带导航 属性 不添加 Id
Ef Code first Index with navigation property without adding Id
我先有一个 EF 代码 class 叫做 UserTag。
UserTag 有以下两个属性
public string TagText { get; set; }
public UserGroup UserGroup { get; set; }
现在我想要一个索引,使 TagText 在 UserGroup 中是唯一的。但是相同的 TagText 应该能够存在于两个不同的用户组中。
我有两个问题,一个是 TagText 不能是它变成的 varchar(max),第二个是我没有 UserGroupId 来连接索引。
我想使用 Fluent API,但可以考虑更改迁移的 Up 和 Down。
但我不想在 TagText 上添加 UserGroupId 和注释。这可能吗?
最好是 Fluent API 但编辑迁移也可以。
编辑:
我没看懂你的问题,我会把我原来的答案留在底部(我看多了,你不想在你的模型中添加外键 属性)。
已编辑答案:
这可以使用流利的 API。
基本上你必须配置 EF 如何将导航属性(用户组)映射到数据库(外键列的名称,它不存在在你的模型中)并在其上放置一个 Index Attribute/Annotation。
为了解决 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; }
}
我暴露了外键属性(信息:我不是100%确定这是否需要,也许放在导航上也可以属性直接)。这按约定工作(通过将 FK 属性 命名为带有 Id 后缀的导航属性。我假设用户组的 Id 是一个整数)。您可以在 msdn 上阅读有关此约定的更多信息(请参阅答案底部的 link)
我还添加了一个 StringLength 属性,否则 EF 通常会创建一个 NVARCHAR(MAX) 列,这在SQL 服务器,因为它超过了最大值。索引长度(正如您在回答中已经提到的那样)。这也将使 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
我先有一个 EF 代码 class 叫做 UserTag。
UserTag 有以下两个属性
public string TagText { get; set; }
public UserGroup UserGroup { get; set; }
现在我想要一个索引,使 TagText 在 UserGroup 中是唯一的。但是相同的 TagText 应该能够存在于两个不同的用户组中。
我有两个问题,一个是 TagText 不能是它变成的 varchar(max),第二个是我没有 UserGroupId 来连接索引。
我想使用 Fluent API,但可以考虑更改迁移的 Up 和 Down。
但我不想在 TagText 上添加 UserGroupId 和注释。这可能吗?
最好是 Fluent API 但编辑迁移也可以。
编辑:
我没看懂你的问题,我会把我原来的答案留在底部(我看多了,你不想在你的模型中添加外键 属性)。
已编辑答案:
这可以使用流利的 API。
基本上你必须配置 EF 如何将导航属性(用户组)映射到数据库(外键列的名称,它不存在在你的模型中)并在其上放置一个 Index Attribute/Annotation。
为了解决 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; }
}
我暴露了外键属性(信息:我不是100%确定这是否需要,也许放在导航上也可以属性直接)。这按约定工作(通过将 FK 属性 命名为带有 Id 后缀的导航属性。我假设用户组的 Id 是一个整数)。您可以在 msdn 上阅读有关此约定的更多信息(请参阅答案底部的 link)
我还添加了一个 StringLength 属性,否则 EF 通常会创建一个 NVARCHAR(MAX) 列,这在SQL 服务器,因为它超过了最大值。索引长度(正如您在回答中已经提到的那样)。这也将使 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