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配置是否存在根本性错误.
从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
初始化程序.
在我看来,这显然是一个错误.
问题始于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_ID
TPT继承名称的索引,最后在发送DDL以创建数据库模式时最终导致数据库中的异常.
EF 4.2(以及之前)根本没有创建任何索引(PK索引除外),这是在EF 4.3中引入的,尤其是FK列的索引.
我没有找到解决方法.在最坏的情况下,您必须手动创建数据库模式,并避免EF尝试创建它(=禁用数据库初始化).在最好的情况下,有一种方法可以禁用自动FK索引创建,但我不知道是否可能.
您可以在此处提交错误报告:http://connect.microsoft.com/VisualStudio
或者EF开发团队的某个人会在这里看到您的问题并提供解决方案.
归档时间: |
|
查看次数: |
2572 次 |
最近记录: |