【问题标题】:Entity Framework Code First, Clustered Indexes & Composite Keys实体框架代码优先、聚集索引和复合键
【发布时间】:2016-05-24 15:10:29
【问题描述】:

我正在尝试使用 EF 的 Code First 方法在表中的复合键使用的列之一上添加非唯一的聚集索引。到目前为止,我有以下模型。请注意我要添加的PackageTarget.PackageId 属性上的IX_PackageTargetPackageId 索引属性:

public class Package
{
    [Key]
    public int Id { get; set; }
    [Required]
    [Index("IX_PackageName", IsUnique = true)]
    public string Name { get; set; }
}

public class Target
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string Value { get; set; }
}

public class PackageTarget
{
    [Key]
    [Column(Order = 0)]
    [Index("IX_PackageTargetPackageId", IsClustered = true)]
    public int PackageId { get; set; }

    [Key]
    [Column(Order = 1)]
    public int TargetId { get; set; }

    [ForeignKey("PackageId")]
    public virtual Package Package { get; set; }

    [ForeignKey("TargetId")]
    public virtual Target Target { get; set; }
}

我有以下自动为我生成的迁移:

CreateTable(
    "dbo.PackageTargets",
    c => new
        {
            PackageId = c.Int(nullable: false),
            TargetId = c.Int(nullable: false),
        })
    .PrimaryKey(t => new { t.PackageId, t.TargetId })
    .ForeignKey("dbo.Packages", t => t.PackageId, cascadeDelete: true)
    .ForeignKey("dbo.Targets", t => t.TargetId, cascadeDelete: true)
    .Index(t => t.PackageId, clustered: true, name: "IX_PackageTargetPackageId")
    .Index(t => t.TargetId);

CreateTable(
    "dbo.Packages",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            Name = c.String(nullable: false)
        })
    .PrimaryKey(t => t.Id)
    .Index(t => t.Name, unique: true, name: "IX_PackageName");

CreateTable(
    "dbo.Targets",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            Value = c.String(nullable: false)
        })
    .PrimaryKey(t => t.Id);

我对迁移所做的唯一修改是将 clustered: false 添加到 PackageTargets 主键,因为我希望将 IX_PackageTargetPackageId 索引改为集群。

经过上述修改,我仍然无法运行迁移,因为出现以下异常:

Cannot create more than one clustered index on table 'dbo.PackageTargets'. 
Drop the existing clustered index 'PK_dbo.PackageTargets' before creating another.

从我的迁移中,我看不到其他聚集索引存在。我错过了什么吗?

【问题讨论】:

    标签: c# .net entity-framework ef-code-first data-annotations


    【解决方案1】:

    你说:

    尝试添加非唯一的聚集索引

    并且在 PackageID 属性上有这个属性:

    [Index("IX_PackageTargetPackageId", IsClustered = true)]
    

    但是您还可以在多个列上定义 [Key] 属性(因为 EF 需要主键),从而创建复合主键。首先在 EF 代码中,不可能(至少不跳过一些环节)定义非聚集主键,因此您的复合主键也将始终是聚集键。

    您不能在一个表上拥有 两个 聚集索引(请参阅这篇 SO 文章:What do Clustered and Non clustered index actually mean?

    聚集索引根据键对磁盘上的行进行物理重新排序,而非聚集索引不进行物理重新排序。由于不可能同时以两种不同的方式对行进行物理排序,因此不能指定两个聚簇索引。

    除非您已完成性能测试并看到手动指定集群密钥的真正好处,否则我建议您将 IsClustered 设置为 false 并允许 EF 管理集群密钥。

    【讨论】:

      【解决方案2】:

      正如 DVK 所说。在您的情况下,EF 试图创建两个不同的聚集索引。第一个聚集为 PK,第二个聚集在索引属性中。您必须进行非集群PK。 不幸的是,在 EF 6 的最新稳定版本中,这可能或不明显。当然,您总是可以将 DbMigration 的 Sql() 方法与纯 SQL 一起使用。但是这个解决方案看起来并不优雅。 EF 6.2的betta版本有这种可能性。

      Install-Package EntityFramework -Version 6.2.0-beta1
      

      然后通过 fluent api 你必须定义 PK 和你的聚集索引。这个例子来自我的项目。

       modelBuilder.Entity<OrderWaybill>()
          .HasKey(o => new { o.GUID, o.OrderDataCode }
                  , config => config.IsClustered(false));
       modelBuilder.Entity<OrderWaybill>()
          .HasIndex("IX_PRIMARY_SELECT", IndexOptions.Clustered
                      , ri=> ri.Property(x=>x.OrderDataCode)
                      , ri => ri.Property(x => x.Number));
      

      【讨论】:

        猜你喜欢
        • 2016-10-17
        • 1970-01-01
        • 1970-01-01
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-04
        • 2011-08-05
        相关资源
        最近更新 更多