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