【发布时间】:2016-10-12 00:16:31
【问题描述】:
我使用 EF6 Code First 定义了四个实体:
public class Item1
{
[Key]
[StringLength(50)]
public string Name { get; set; }
}
public partial class Item2
{
[Key]
[Column(Order = 0)]
[StringLength(50)]
public string Item1Name { get; set; }
[Key]
[Column(Order = 1)]
[StringLength(50)]
public string Name { get; set; }
}
public partial class Item3
{
[Key]
[Column(Order = 0)]
[StringLength(50)]
public string Item1Name { get; set; }
[Key]
[Column(Order = 1)]
[StringLength(50)]
public string Item2Name{ get; set; }
[Key]
[Column(Order = 2)]
[StringLength(50)]
public string Name { get; set; }
}
public partial class Item4
{
[Key]
[Column(Order = 0)]
[StringLength(50)]
public string Item1Name { get; set; }
[Key]
[Column(Order = 1)]
[StringLength(50)]
public string Item2Name{ get; set; }
[Key]
[Column(Order = 2)]
[StringLength(50)]
public string Item3Name{ get; set; }
[Key]
[Column(Order = 3)]
[StringLength(50)]
public string Name{ get; set; }
}
(我省略了导航属性,但它们在那里。)
这样定义的关系:
modelBuilder.Entity<Item1>()
.HasMany(e => e.Item2s)
.WithRequired(e => e.Item1)
.HasForeignKey(e => new { e.Item1Name})
.WillCascadeOnDelete(false);
modelBuilder.Entity<Item2>()
.HasMany(e => e.Item3s)
.WithRequired(e => e.Item2)
.HasForeignKey(e => new { e.Item1Name, e.Item2Name })
.WillCascadeOnDelete(false);
modelBuilder.Entity<Item3>()
.HasMany(e => e.Item4s)
.WithRequired(e => e.Item3)
.HasForeignKey(e => new { e.Item1Name, e.Item2Name, e.Name})
.WillCascadeOnDelete(false);
现在,当我尝试像这样将 Item3 插入到 existingItem2.Item3s 中时:
Item3 newItem3 = new Item3();
newItem3.Item4s.Add(new Item4());
existingItem2.Item3s.Add(newItem3);
db.SaveChanges();
我收到以下错误:
无法将值 NULL 插入到列“Item1Name”、表“Database.dbo.Item4s”中;列不允许空值。 INSERT 失败。\r\n语句已终止。
奇怪的是,在没有嵌套 Item4 的情况下将 Item3 插入到 existingItem2.Item3s 中后,我可以使用上述过程插入嵌套项目而不会出现任何错误。我试过用[DatabaseGenerated(DatabaseGeneratedOption.None)] 明确指定所有键,但这没有区别。这里有什么可以玩的?
编辑
我缩小了错误的范围,以及为什么它有时会发生有时不会发生。在我的程序中,除了我所描述的之外,我还设置了existingItem2.someUnrelatedNonKeyIntegerValue = someValue;。事实证明,如果这实际上会改变值(它总是被设置),EF 将生成一个失败的查询。似乎是EF中的一个错误,对吗?我是这样解决它的:
if (existingItem2.someUnrelatedNonKeyIntegerValue != someValue)
{
existingItem2.someUnrelatedNonKeyIntegerValue = someValue;
db.SaveChanges();
}
Item3 newItem3 = new Item3();
newItem3.Item4s.Add(new Item4());
existingItem2.Item3s.Add(newItem3);
db.SaveChanges();
(顺便说一下,整数名称中不包含ID,并且确实没有标记为数据库中的键。)
【问题讨论】:
-
您是否需要按原样使用数据模型?它的设计真的很糟糕,这可能是你的一些痛苦的原因。每个表都应该有一个代理键,它成为层次结构中下一个表的外键。从长远来看,修复数据库的设计可能会解决您的问题并为您提供更好的结构。
-
我同意 Craig W 的观点。这个简单的模型已经给你带来了问题。我们甚至没有谈论性能。我怀疑这是 EF 中的一个错误,更有可能它不是为那样使用而设计的。出于最好的考虑,我建议您下载 EF6 教程并花一些时间从中学习,而不是寻找解决方法。这是一个:asp.net/mvc/overview/getting-started/… 请注意,键是 int 类型和名称 Id 的单个属性。
-
@RuardvanElburg 谢谢,但我已经很熟悉了。事实上,在我将其重构为当前设计之前,我就是这样做的。识别数据库设计中的关系不是我自己提出的结构,EF 以多种方式支持它。例如,如果与父级的关系正在识别 (stackoverflow.com/a/17726414/6452047),则 DBSet.Remove() 会自动删除实体。
-
@CraigW。不是必需的,但这很有意义,因为我主要根据用户通过 Web API 调用发送的父 item1 和 item2 的名称进行大量查询来检索 Item3 对象。
标签: c# .net sql-server entity-framework entity-framework-6