在EntityFramework中克隆具有多对多关系的对象
本文关键字:关系 对象 EntityFramework | 更新日期: 2023-09-27 17:58:23
我只想创建一个对象的精确副本。
我有一个类
[Serializable]
public class Project
{
public int Id { get; set; }
public String Name { get; set; }
//navigational fields..
public virtual List<BusinessRequirement> BusinessRequirements { get; set; }
}
和另一个
[Serializable]
public class BusinessRequirement
{
public int Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public virtual List<Project> Projects { get; set; }
}
所以在某个地方,我配置了多对多关系b/w Project
和BusinessRequirement
,如下所示:
HasMany(s => s.BusinessRequirements)
.WithMany(s => s.Projects)
.Map(m =>
{
m.MapLeftKey("ProjectId");
m.MapRightKey("BusinessRequirementId");
m.ToTable("ProjectBusinessRequirementMapping");
});
此外,我还将我的dbcontext设置为静态,即
public static class DataLayer
{
public static MyDbContext db;
}
现在,我所做的就是,试图复制Project
的对象,即
public Project Clone(Project source)
{
Project target = new Project();
target.Name = source.Name;
//1.
// target = source;
//2.
target.BusinessRequirements = new List<BusinessRequirement>();
foreach(BusinessRequirement br in source.BusinessRequirements)
{
BusinessRequirement nbr = DataLayer.Get<BusinessRequirement>(s=>s.Id=br.Id).SingleOrDefault();
if(nbr!=null)
target.BusinessRequirements.Add(nbr);
}
//3.
//target.BusinessRequirements = source.BusinessRequirements;
//4.
//target.BusinessRequirements = new List<BusinessRequirement>();
//foreach(BusinessRequirement br in source.BusinessRequirements)
//{
// BusinessRequirement nbr = br;
// if(nbr!=null)
// target.BusinessRequirements.Add(nbr);
//}
return target;
}
这四种方法都不能正常工作。
最接近工作的是2,但发生了一件奇怪的事情。现在,若我将任何BusinessRequirements添加到Original Project
,它也会被添加到Clonned One
,反之亦然,删除也是如此。
不知何故,实体框架将这两个项目视为一个项目。尽管这种行为只发生在多对多相关的导航属性中。
为什么EntityFramework会这样???。我错过了什么?请帮忙。。
已经快一天了,但我不能让它去上班。
我试过这个,这个,这个和这个,但它们也不起作用。。
您可以使用这样一个事实:将对象添加到上下文会将其对象图中任何子对象的状态更改为Added
:
Project proj;
using (var db = new MyDbContext())
{
// Fetch a detached project and populate its BusinessRequirements.
proj = db.Projects.AsNoTracking().Include(p => p.BusinessRequirements)
.First(p => p.Id == source.Id);
db.Projects.Add(proj);
db.SaveChanges();
}
通过使用AsNoTracking
获取源项目,上下文不会将其添加到其更改跟踪器中,并且下一行db.Projects.Add(proj);
将该项目及其附属子对象视为全新的。
我默默地放弃了你在一个静态环境下工作的策略。这是一个不同的话题,但你不应该那样做。上下文的寿命应该很短。
问题是由于您复制BusinessRequirement的方式造成的。您只是将引用从源添加到目标。因此,每个BusinessRequirement最终都引用了这两个项目。
你需要做这样的事情。
target.BusinessRequirements = new List<BusinessRequirement>();
foreach(BusinessRequirement br in source.BusinessRequirements)
{
BusinessRequirement obr = DataLayer.Get<BusinessRequirement>(s=>s.Id=br.Id).SingleOrDefault();
BusinessRequirement obr = new BuisnessRequirment();
if(nbr!=null){
//copy protperies in obr to nbr
}
target.BusinessRequirements.Add(nbr);
}