10

错误:

未处理的异常:System.Data.SqlClient.SqlException:操作失败,因为表 'PrivateMakeUpLessons' 上已存在名称为 'IX_ID' 的索引或统计信息。

模型(简化,构建在单独的测试项目中进行调试):

public abstract class Lesson
{
    public Guid ID { get; set; }
    public string Room { get; set; }
    public TimeSpan Time { get; set; }
    public int Duration { get; set; }
}

public abstract class RecurringLesson : Lesson
{
    public int DayOfWeek { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public string Frequency { get; set; }
}

public class PrivateLesson : RecurringLesson
{
    public string Student { get; set; }
    public string Teacher { get; set; }
    public virtual ICollection<Cancellation> Cancellations { get; set; }
}

public class Cancellation
{
    public Guid ID { get; set; }
    public DateTime Date { get; set; }
    public virtual PrivateLesson Lesson { get; set; }
    public virtual MakeUpLesson MakeUpLesson { get; set; }
}

public class MakeUpLesson : Lesson
{
    public DateTime Date { get; set; }
    public string Teacher { get; set; }
    public virtual Cancellation Cancellation { get; set; }
}

配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Lesson>().ToTable("Lessons");
    modelBuilder.Entity<RecurringLesson>().ToTable("RecurringLessons");
    modelBuilder.Entity<PrivateLesson>().ToTable("PrivateLessons");
    modelBuilder.Entity<MakeUpLesson>().ToTable("PrivateMakeUpLessons");

    modelBuilder.Entity<Cancellation>()
        .HasOptional(x => x.MakeUpLesson)
        .WithRequired(x => x.Cancellation);

    base.OnModelCreating(modelBuilder);
}

备注

这在 EF 4.2 中运行良好。我的模型有问题吗?实际模型要复杂得多,这就是我将所有类抽象出来的原因。此外,我正在针对现有数据库工作,因此我需要使用 Table-Per-Type 继承。

如果我将Cancellationto的关系PrivateMakeUpLesson从 1 更改为 0..1 到 0..1 到 0..1,它就可以工作。这是不可取的,因为你不能PrivateMakeUpLesson没有 a Cancellation

此外,如果我让PrivateMakeUpLessonNOT 继承,Lesson它也可以工作,但这是一个教训,需要为现有的业务逻辑保持这种状态。

我会很感激任何指导。谢谢!

编辑

开始赏金。我找不到任何关于 EF 4.2 和 EF 4.3 之间关于代码优先索引生成的变化的文档。很明显,EF 4.3 正在创建更多索引并且命名方案已更改,但我想知道 EF 中是否存在错误,或者我的模型或流畅的 API 配置是否存在根本性错误。

4

5 回答 5

9

从 EF 4.3 开始,在数据库创建期间为外键列添加索引。有一个错误可能导致索引被多次创建。这将在未来的 EF 版本中修复。

在此之前,您可以通过使用迁移而不是数据库初始化程序(或Database.Create()方法)创建数据库来解决此问题。

生成初始迁移后,您需要删除对Index().

CreateTable(
    "dbo.PrivateMakeUpLessons",
    c => new
        {
            ID = c.Guid(nullable: false),
            ...
        })
    .PrimaryKey(t => t.ID)
    .ForeignKey("dbo.Lessons", t => t.ID)
    .ForeignKey("dbo.Cancellations", t => t.ID)
    .Index(t => t.ID)
    .Index(t => t.ID); // <-- Remove this

要在运行时继续创建数据库,您可以使用MigrateDatabaseToLatestVersion初始化程序。

于 2012-05-14T22:33:48.067 回答
5

在我看来,这显然是一个错误。

问题始于观察到 EFIX_ID完全创建索引。如果您将模型简化为以下...

public abstract class Lesson
{
    public Guid ID { get; set; }
}

public class RecurringLesson : Lesson
{
}

public class MyContext : DbContext
{
    public DbSet<Lesson> Lessons { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<RecurringLesson>().ToTable("RecurringLessons");
    }
}

...并让 EF 创建数据库架构,您将获得两个表Lessons,并且RecurringLessons符合 TPT 继承映射的预期。但我想知道为什么它为表创建两个索引RecurringLessons

  • 具有索引列的索引PK_RecurringLessons(聚集的、唯一的)ID
  • 再次使用索引列索引IX_ID(非聚集,非唯一)ID

我不知道数据库在同一列上有第二个索引是否有任何好处。但据我了解,这没有意义 1)在 PK 聚集索引中已经涵盖的同一列上创建索引,以及 2)在作为主键的列上创建非唯一索引,因此必须独特。

此外,由于一对一的关系,EF 试图在该关联的依赖表上创建一个索引,即PrivateMakeUpLessons. (它是依赖项(而不是委托人),因为在 entity 中Cancellation必需MakeUpLesson的。)

ID是此关联中的外键(同时也是主键,因为在实体框架中,一对一的关系始终是共享的主键关联)。EF 显然总是在关系的外键上创建索引。但对于一对多关系,这不是问题,因为 FK 列与 PK 列不同。一对一的关系并非如此:FK 和 PK 是相同的IDIX_ID即从数据库的角度来看也是一对一的关系)。

与上述相同的考虑在这里适用:该表PrivateMakeUpLessons在 column 上有一个聚集的 PK 索引ID。为什么根本IX_ID需要同一列上的第二个索引?

此外,EF 似乎并没有检查它是否已经想IX_ID为 TPT 继承创建一个带有名称的索引,最终导致在发送 DDL 以创建数据库模式时数据库中出现异常。

EF 4.2(及之前)根本没有创建任何索引(PK 索引除外),这是在 EF 4.3 中引入的,尤其是 FK 列的索引。

我没有找到解决方法。在最坏的情况下,您必须手动创建数据库架构并避免 EF 尝试创建它(= 禁用数据库初始化)。在最好的情况下,有一种方法可以禁用自动 FK 索引创建,但我不知道这是否可能。

您可以在此处提交错误报告:http ://connect.microsoft.com/VisualStudio

或者,也许 EF 开发团队的某个人会在这里看到您的问题并提供解决方案。

于 2012-05-11T12:29:47.063 回答
2

不久前,我在代码中遇到了与此错误非常相似的错误。尝试将取消列表放入课程课程中。这就是解决我的问题的方法。

于 2012-05-09T19:15:28.600 回答
2

下面我描述了 2 个可能出现问题的场景。请通过单击我提供的链接深入阅读以了解有关我的解释的更多信息。


首先
LessonRecurringLessonabstract类(所以你想把它作为基类)。
您正在创建一个表LessonRecurringLesson实体,这将导致每个层次结构的表。 简要说明
创建一个基表类将产生一个包含所有继承表的列的大表。因此 的所有属性PrivateLesson以及MakeUpLesson所有其他继承的实体都将存储在Lessons表中。EF 还将添加一个Discriminator柱子。此列的值默认为持久类名称(如“PrivateLesson”或“MakeUpLesson”),只有与该特定实体匹配的列(匹配鉴别器值)才会在该特定行中使用。

但是
您也在映射继承的类,如PrivateLessonMakeUpLesson。这将强制 EF 使用Table per Type结构,这会导致每个类一个表。这可能会导致您现在面临的冲突。


其次
,您的示例显示您具有一对一关系(Cancellation -> MakeUpLesson)和一对多关系(Cancellation -> PrivateLesson),因为PrivateLessonMakeUpLesson都是(间接)继承自Lesson与第一个描述的场景相结合可能会导致问题,因为它会导致 2每个实体的数据库中的外键关系。(一个使用Table per 层次结构,一个使用Table per Type结构)。

此外,这篇文章可以帮助您定义正确的一对一定义。


请通过执行以下步骤进行验证:
我假设您有自己的测试环境,因此您可以创建新的测试数据库

1.Cancellation通过注释掉这个类的所有属性来 删除与 的关系:

public class PrivateLesson : RecurringLesson
{
    public string Student { get; set; }
    public string Teacher { get; set; }
    //public virtual ICollection<Cancellation> Cancellations { get; set; }
}

public class Cancellation
{
    public Guid ID { get; set; }
    public DateTime Date { get; set; }
    //public virtual PrivateLesson Lesson { get; set; }
    //public virtual MakeUpLesson MakeUpLesson { get; set; }
}

public class MakeUpLesson : Lesson
{
    public DateTime Date { get; set; }
    public string Teacher { get; set; }
    //public virtual Cancellation Cancellation { get; set; }
}

并删除它的配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Lesson>().ToTable("Lessons");
    modelBuilder.Entity<RecurringLesson>().ToTable("RecurringLessons");
    modelBuilder.Entity<PrivateLesson>().ToTable("PrivateLessons");
    modelBuilder.Entity<MakeUpLesson>().ToTable("PrivateMakeUpLessons");

    //modelBuilder.Entity<Cancellation>()
    //    .HasOptional(x => x.MakeUpLesson)
    //    .WithRequired(x => x.Cancellation);

    base.OnModelCreating(modelBuilder);
}

2. 新建一个空数据库
3. 让EF在这个空数据库中为你生成表结构。
4. 验证第一个场景。如果这是真的,这需要首先使用Table per hierarchy structureTable per Type structure来解决。可能您想使用每个层次结构的表,因为(如果我很好地理解您的问题)已经有一个生产环境。

于 2012-05-11T10:08:11.253 回答
1

当我的项目从EF 6.0.2更新到EF 6.1.1时,出现了这样的问题,然后回到6.0.2,返回旧版本后,错误消失了

于 2014-08-05T05:34:01.213 回答