我使用实体框架4.4和我有一个一对多的关系模型是这样的:
类项目{公共字符串keyPart1 {搞定;组; } 公共字符串keyPart2 {搞定;组; } 公共虚拟集装箱货柜{搞定;组; } 公共字符串ContainerId {搞定;组; } } //想法是,许多项目将被分配到一个容器级集装箱{公共字符串ContainerId {搞定;组; } 私人的ICollection<项目> _items; 公共虚拟的ICollection<项目>由于 { {返回_items? (_items =新的HashSet< A>()); } 保护集合{_items =价值; } } }现在,这里的的DbContext:
公共类StorageContext:的DbContext {公共DbSet<项目>项目{搞定;组; } 公共DbSet<铲斗和GT;水桶{搞定;组; } 公共覆盖无效OnModelCreating(DbModelBuilder模型构建器) { base.OnModelCreating(模型构建器); modelBuilder.Entity<项目方式>()HasKey(I =>新建{i.keyPart1,i.keyPart2}).HasRequired(I => i.Container); } }现在,假设我有N个项目实例。每个项属于一个容器,其包含多个项目的情况下,其中每一个属于一个容器,因此模型无休止递归
欲再通过循环我项目实例当前列表以及每个添加到数据库方面:
的foreach(VAR我在LocalItemList) { IDbSetExtensions.AddOrUpdate<项目>(db.Items,I); } dbContext.SaveChanges();这是我想不通的问题是如何告诉上下文 AddOrUpdate 的集装箱让我不明白的主键重复异常。在某些时候,我们会碰到一个项目具有相同的集装箱作为另一个,但我会得到一个复制了的SaveChanges主键异常()。
如果我添加集装箱到DbSet,是项目增补的设置呢?我怎么能作出这样的 AddOrUpdate 呢?
解决方案我不相信如果你想插入相关集装箱 s转换数据库随着项目 S,或者如果你只是想创建一个关系到现有的集装箱秒。该集装箱实体没有在数据库中,并在你的对象图,你只能有一个集装箱 实例的每个键(多的引用的这些实例允许)不应该在所有的问题,一个简单的代码一样...
的foreach(VAR我在LocalItemList) { dbContext.Items.Add(I) } dbContext.SaveChanges();
...实际上应该无一例外地工作。所以,你可能有以下两种情况之一这可以解释主键约束冲突:
-
的容器实体已经存在于数据库中,并在你的对象图,你只能有一个集装箱的实例(多重的引用的这些实例再次允许的)。这是最简单的情况下,你可以通过使用解决它:
的foreach(VAR我在LocalItemList) { dbContext.Containers.Attach(i.Container); dbContext.Items.Add(ⅰ); } dbContext.SaveChanges();如果您有多个集装箱实例相同的密钥,这将无法工作,抛出的......具有相同键的对象已存在于ObjectContext的......的(或类似)异常。它也不会工作,如果集装箱•不要在数据库中还不存在(你可能会得到一个违反外键约束的话)。
-
如果您有多个集装箱对象实例在你的对象图相同的密钥必须通过每一个唯一实例替换重复关键你连接或实体添加到上下文之前。为了使这个过程更简单我会先删除循环引用,然后使用本地收集找出如果一个集装箱使用相同的密钥已经被附:
的foreach(VAR我在LocalItemList) {我。 Container.Items = NULL; VAR attachedContainer = dbContext.Containers.Local .SingleOrDefault(C => c.ContainerId == i.Container.ContainerId); 如果(attachedContainer!= NULL) i.Container = attachedContainer; ,否则 dbContext.Containers.Attach(i.Container); //或dbContext.Containers.Add(i.Container); //取决于如果要插入容器或没有 dbContext.Items.Add㈠; } dbContext.SaveChanges();
I'm using Entity Framework 4.4 and I have a One-To-Many relationship model like this:
class Item { public string keyPart1 { get; set; } public string keyPart2 { get; set; } public virtual Container container { get; set; } public string ContainerId { get; set; } } // Idea is that many Items will be assigned to a container class Container { public string ContainerId { get; set; } private ICollection<Item> _Items; public virtual ICollection<Item> As { get { return _Items ?? (_Items = new HashSet<A>()); } protected set { _Items = value; } } }Now, here's the DbContext:
public class StorageContext : DbContext { public DbSet<Item> Items { get; set; } public DbSet<Bucket> Buckets { get; set; } public override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Item>().HasKey( i => new { i.keyPart1, i.keyPart2 } ).HasRequired( i => i.Container ); } }Now, supposing I have N Item instances. Each Item belongs to a container, which contains multiple item instances, each of which belongs to a container, and so the model recurses endlessly.
I want to then cycle through my current list of Item instances and add each to the db context:
foreach (var i in LocalItemList) { IDbSetExtensions.AddOrUpdate<Item>(db.Items, i); } dbContext.SaveChanges();The problem that I can't figure out is how to tell the context to AddOrUpdate the Container so that I don't get primary key duplicate exceptions. At some point we'll run into an Item that has the same Container as another, but I'll get a duplicate primary key exception on SaveChanges().
If I Add a Container to the DbSet, are the Items added to the Set as well? How can I make that an AddOrUpdate instead?
解决方案I am not sure if you want to insert the related Containers into the database along with the Items, or if you only want to create a relationship to already existing Containers. The possible case that the Container entities do not exist in the database and in your object graph you only have one Container instance per key (multiple references to those instances are allowed) should not be a problem at all and a simple code like...
foreach (var i in LocalItemList) { dbContext.Items.Add(i); } dbContext.SaveChanges();...should actually work without exception. So, you probably have one of the following two situations which would explain the primary key constraint violation:
The Container entities already exist in the database and in your object graph you only have one Container instance per key (multiple references to those instances are allowed again). This is the easy case and you can solve it by using:
foreach (var i in LocalItemList) { dbContext.Containers.Attach(i.Container); dbContext.Items.Add(i); } dbContext.SaveChanges();If you have multiple Container instances for the same key this won't work and throw an "...an object with the same key already exists in the ObjectContext..." (or similar) exception. It also won't work if the Containers do not exist yet in the database (you'll probably get a foreign key constraint violation then).
If you have multiple Container object instances with the same key in your object graph you must replace the duplicates by one unique instance per key before you attach or add the entities to the context. To make this process simpler I would remove the circular references first and then use the Local collection to figure out if a Container with the same key is already attached:
foreach (var i in LocalItemList) { i.Container.Items = null; var attachedContainer = dbContext.Containers.Local .SingleOrDefault(c => c.ContainerId == i.Container.ContainerId); if (attachedContainer != null) i.Container = attachedContainer; else dbContext.Containers.Attach(i.Container); // or dbContext.Containers.Add(i.Container); // depending on if you want to insert the Container or not dbContext.Items.Add(i); } dbContext.SaveChanges();
更多推荐
如何实体添加到的DbContext递归关系,同时避免重复补充?
发布评论