在EntityFramework中克隆具有多对多关系的对象

时间:2013-02-09 16:14:19

标签: c# linq clone entity-framework-5

我想要的只是创建一个对象的精确副本。

我有一个班级

[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 ProjectBusinessRequirement,如下所示:

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,但奇怪的事情发生了。 现在,如果我向Original Project添加任何BusinessRequirements,它也会被添加到Clonned One,反之亦然,同样也可以删除。

不知何故,entityframework将这两个项目视为一个项目。虽然此行为仅出现在多对多相关的导航属性中。

为什么EntityFramework表现得像这样?我错过了什么?请帮忙..

差不多有一天了,但是我无法让它发挥作用。

我尝试了thisthisthisthis,但他们也没有工作..

2 个答案:

答案 0 :(得分:2)

您可以使用以下事实:将对象添加到上下文会将其对象图中任何子对象的状态更改为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);会将项目及其附加的子对象视为全新的。

默默地,我放弃了使用一个静态上下文的策略。这是一个不同的主题,但你不应该这样做。上下文的寿命应该很短。

答案 1 :(得分:0)

由于您复制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);
         }