升级到Entity Framework 4.3.1后出现未处理的异常

Luc*_*Sam 10 c# entity-framework ef-code-first

错误:

未处理的异常: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; }
}
Run Code Online (Sandbox Code Playgroud)

组态:

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);
}
Run Code Online (Sandbox Code Playgroud)

备注:

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

如果我改变的关系Cancellation,以PrivateMakeUpLesson从1到0..1到0..1到0..1它的工作原理.这是不可取的,因为你PrivateMakeUpLesson没有a Cancellation.

此外,如果我从那时起PrivateMakeUpLesson不继承,Lesson它也可以工作,但这是一个教训,需要保持现有的业务逻辑.

我很感激任何指导.谢谢!

编辑:

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

bri*_*lam 9

从EF 4.3开始,在数据库创建期间为freign键列添加索引.有一个错误可能导致索引被多次创建.这将在未来的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
Run Code Online (Sandbox Code Playgroud)

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


Sla*_*uma 5

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

问题始于EF IX_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");
    }
}
Run Code Online (Sandbox Code Playgroud)

...让EF创建数据库模式,获得两个表Lessons,RecurringLessons并按预期进行TPT继承映射.但我想知道为什么它为表创建两个索引RecurringLessons:

  • PK_RecurringLessons索引列的索引(聚簇,唯一)ID
  • 指数IX_ID(不聚集,不唯一)与索引列ID再次

我不知道数据库在同一列上有第二个索引是否有任何好处.但是根据我的理解,1)在PK聚簇索引中已经覆盖的同一列上创建索引,以及2)在作为主键的列上创建非唯一索引并因此必然独特.

此外,由于一对一的关系,EF尝试在该关联的依赖表上创建索引PrivateMakeUpLessons.(这是依赖(而非主体),因为在实体中Cancellation必需MakeUpLesson.)

ID是此关联中的外键(同时是主键,因为一对一关系始终是实体框架中的共享主键关联).EF显然总是在关系的外键上创建索引.但对于一对多关系,这不是问题,因为FK列与PK列不同.对于一对一关系并非如此:FK和PK是相同的(即ID),因此EF尝试IX_ID为这种一对一关系创建索引,该关系由于TPT继承映射已经存在(这导致从数据库角度看一对一的关系).

与上述相同的考虑适用于此:表PrivateMakeUpLessons在列上具有聚簇PK索引ID.为什么IX_ID需要同一列的第二个索引呢?

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

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

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

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

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