实体框架在播种数据库上插入重复项[重复]
Posted
技术标签:
【中文标题】实体框架在播种数据库上插入重复项[重复]【英文标题】:Entity Framework inserting duplicates on Seeding database [duplicate] 【发布时间】:2019-05-11 10:20:26 【问题描述】:编辑----
来自here,我尝试在播种方法中分配 ID,这对于语言来说是可以的,但是当我向客户添加地址并将 ID 也分配给这些地址时,它创建了又被骗了……
地址和语言都在我的上下文中声明为 DbSet<...>
我尝试了什么:
添加 1 个地址(带有 ID)- 将此添加到 1 个客户 => 创建一个 欺骗 添加 1 种语言和 1 个地址(带有 ID) - 将两者都添加到 1 位客户 => 创建一个骗子 添加 1 个只有名称的客户 => 不创建 欺骗 添加 1 种语言(带有 ID) - 将此添加到 1 个客户 => 不 创建一个副本我的 Customer 上有一个 Override ToString() 方法,它返回它的名称,我可以观察到,当我在调试 1 的名称时查看副本时,另一个是 Customer 类所在的命名空间,它似乎是 loguc,因为在 Dupes 案例中 Name 为 NULL 但我还是想提一下...
----编辑
我正在用一些元数据为我的数据库播种,我发现它有一种我以前从未见过的非常奇怪的行为。我正在插入一个实体“客户”,它插入了这个实体 2 次,第一次插入是正确的并且具有它应该具有的所有内容,另一个具有 NULL 属性(字符串值)但有些(如日期时间)具有值。
我完全不知道为什么会这样,当我调用 base.Seed(ctx);方法,我敢肯定,因为我在此之后停止了 Webapp,然后才到达其他任何地方。
此实体客户具有相关的实体语言以及地址集合。
我有another post open(还没有建议),同样的问题发生在哪里,这突然发生了,我自己没有对我的模型或播种方法做任何改变......
基础实体:
public class BaseEntity
public int ID get; set;
客户:
public class Customer:BaseEntity
public string Name get; set;
public Language Language get; set;
public ICollection<Address> Addresses get; set;
语言:
public class Language : BaseEntity
public string Name get; set;
public string LanguageCode get; set;
[Required]
public ICollection<Customer> Customers get; set;
地址:
public class Address : BaseEntity
public Customer Customer get; set;
播种方法:
Language newLanguageNL = new Language("Dutch");
newLanguageNL.ID = 1;
Language newLanguageFR = new Language("French");
newLanguageFR.ID = 2;
Language newLanguageEN = new Language("English");
newLanguageEN.ID = 3;
ctx.Languages.Add(newLanguageNL);
ctx.Languages.Add(newLanguageEN);
ctx.Languages.Add(newLanguageFR);
Address addressBE = new Address("informatica laan", "10", "bus nr 1", "8900", "België");
addressBE.ID = 1;
Address addressBE2 = new Address("rue de l'informatique", "20", "boite nr 2", "7780", "Belgique");
addressBE2.ID = 2;
Address addressEN = new Address("techstreet", "30", "box nr 1", "4000", "Bulgaria");
addressEN.ID = 3;
ctx.Addresses.Add(addressEN);
ctx.Addresses.Add(addressBE);
ctx.Addresses.Add(addressBE2);
Customer newCustomer = new Customer("Customer name", newLanguageNL, addressBE);
// ctx.Customers.AddOrUpdate(c => c.Name, newCustomer);
ctx.Customers.Add(newCustomer);
base.Seed(ctx);
OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
// setting the Product FK relation required + related entity
modelBuilder.Entity<Entity.ProductSupplierForContract>().HasRequired(psfc => psfc.Product)
.WithMany(p => p.ProductSupplierForContracts)
.HasForeignKey(psfc => psfc.Product_Id);
// setting the Supplier FK relation required + related entity
modelBuilder.Entity<Entity.ProductSupplierForContract>().HasRequired(psfc => psfc.Supplier)
.WithMany(s => s.ProductSupplierForContracts)
.HasForeignKey(psfc => psfc.Supplier_Id);
// setting the Contract FK relation required + related entity
modelBuilder.Entity<Entity.ProductSupplierForContract>().HasOptional(psfc => psfc.Contract)
.WithMany(c => c.ProductSupplierForContracts)
.HasForeignKey(psfc => psfc.Contract_Id);
modelBuilder.Entity<Entity.PurchasePrice>()
.ToTable("PurchasePrices");
modelBuilder.Entity<Entity.SalesPrice>()
.ToTable("SalesPrices");
// Bundle in Bundle
modelBuilder.Entity<Entity.Bundle>().HasMany(b => b.ChildBundles);
谁能帮我解决这个问题,提前感谢您的任何反馈。 我试过使用 AddOrUpdate() 没有运气。
【问题讨论】:
缺少您的 BaseEntity 类以及您如何插入客户实体。 @pnet,你是对的,对此我很抱歉,我更新了所有内容并添加了更多信息。 再次更新了新结果 是什么让您期望代码每次不会插入新客户? (以及其他一切,就此而言,假设某处SaveChanges
被调用)。正如种子代码中所预期的那样,我没有看到对现有实体的任何检查,并且AddOrUpdate
被注释掉了。另外,我强烈建议将这两个问题合并为一个minimal reproducible example。到目前为止,经过所有这些编辑,这个问题很难理解,副本的状态也不清楚。另外(2)你的描述让我怀疑你在构造函数中初始化了引用属性。
***.com/a/20773057/861716
【参考方案1】:
因此,将实体 Customer 的 Address 类中的关系更改为 ICollection 而不是 1 Single Customer 不会创建欺骗(并创建一个 CustomerAddress 表,该表我其实也想要)。
从数据库日志 (log4net) 看来,由于关系 EF 首先为客户的地址引用插入客户 (NULL),并插入客户 (NOT NULL) 及其引用......当我比较地址和语言我看到语言也有一个客户集合(地址没有),这解释了为什么地址创建了重复的客户条目。 (如果有人需要对此进行任何澄清,请告诉我我会尽力而为)
此帖HAS MOVED TO HERE
我要感谢所有以任何方式做出贡献的人!
【讨论】:
【参考方案2】:我发现您的代码存在一些问题。按照惯例,一个名为 ID 的 int
列将是一个标识列,因此您不能在不发出 SET IDENTITY_INSERT Language ON
的情况下明确设置它的 ID(除非您有流畅的代码覆盖它)。
AddOrUpdate
适用于这些情况。您还没有显示该代码。另一种方式如下所示:
...
if (!ctx.Languages.Any(l => l.ID == 1)) // Check if already on file
ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT Language ON"); // Omit if not identity column
var dutch = new Language
ID = 1,
Name = "Dutch",
Code = "NL"
;
ctx.Languages.Add(dutch);
ctx.SaveChanges();
ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT Language OFF"); // Omit if not identity column
... repeat for other languages
... similar code for other seeded tables
【讨论】:
这是正确的,但由于我每次都删除我的数据库(开始清理)我可以自己设置它们(手动自动递增它们),这可以工作,因为我可以看到他们有我分配给他们的 ID .除了 cmets 中的内容(关于 AddOrUpdate),我还应该展示什么?我知道在使用它时我不能使用 ID 属性,但仅此而已......我还尝试使用 ctx.Customers.Local 检查它是否在本地存在......但检查时它不存在所以我会实施您的建议并提供反馈。唯一的问题是添加地址时,其他人工作正常(没有欺骗)【参考方案3】:您的地址和语言会保留在您向客户提供建议的地方。我认为在您的构造函数中,您会向客户建议收藏品,不是吗? 这是不必要的。您可以在没有明确建议集合的情况下保留客户。 EF 将自行映射集合。
【讨论】:
我确实是通过构造函数添加地址实体,填充 Address = new HashSet() address ;但删除它并没有帮助。在游戏中添加地址时我仍然有一个欺骗......(感谢您的建议) 您的实体映射如何? 我更新了原帖;) 映射与类定义不匹配。你能纠正一下吗? 也许这就是问题所在。将您的映射附加到模型创建映射。我知道选择查询中有一个自动完成功能,其中没有映射。也许这也会发生在这里。以上是关于实体框架在播种数据库上插入重复项[重复]的主要内容,如果未能解决你的问题,请参考以下文章