复制实体框架对象

时间:2011-08-24 08:45:40

标签: c# entity-framework

我有一个EF4.1类X,我想复制它以及它的所有子记录。 X.Y和X.Y.Z

现在,如果我执行以下操作,则会返回错误。

属性“X.ID”是对象密钥信息的一部分,无法修改。

public void CopyX(long ID)
{
    var c = db.Xs.Include("Y").Include("W").Include("Y.Z").SingleOrDefault(x => x.ID == ID);
    if (c != null)
    {
        c.ID = 0;
        c.Title = "Copy Of " + c.Title;
        for (var m = 0; m < c.Ys.Count; m++)
        {
            c.Ys[m].ID = 0;
            c.Ys[m].XID=0-m;
            for (var p = 0; p < c.Ys[m].Zs.Count; p++)
            {
                c.Ys[m].Zs[p].XID = 0 - m;
                c.Ys[m].Zs[p].ID = 0 - p;
            }
        }
        for (var i = 0; i < c.Ws.Count; i++)
        {
            c.Ws[i].ID = 0 - i;
            c.Ws[i].XID = 0;
        }
        db.Entry<Content>(c).State = System.Data.EntityState.Added;
        db.SaveChanges();
    }
}

或是否有其他方式制作实体对象的副本。

注意:每个W,X,Y,Z都有多个属性。

5 个答案:

答案 0 :(得分:27)

中,使用DbExtensions.AsNotracking()非常容易。

  

返回一个新查询,其中返回的实体不会缓存在DbContext或ObjectContext中。

这似乎是对象图中所有对象的情况。

您只需要真正了解您的图表,以及您不希望将其插入/复制到数据库中。

让我们假设我们有像这样的对象:

public class Person
{
  public int ID { get; set; }
  public string Name { get; set; }
  public virtual ICollection<Address> Addresses { get; set; }
}

public class Address
{
  public int ID { get; set; }
  public AddressLine { get; set; }
  public int StateID { get; set; }

  public ICollection<State> { get; set; }
}

因此,为了复制一个人,我需要复制地址,但我不想复制这些状态。

var person = this._context.Persons
  .Include(i => i.Addresses)
  .AsNoTracking()
  .First();

// if this is a Guid, just do Guid.NewGuid();
// setting IDs to zero(0) assume the database is using an Identity Column
person.ID = 0;

foreach (var address in person.Addresses)
{
  address.ID = 0;
}

this._context.Persons.Add(person);
this._context.SaveChanges();

如果您希望再次重复使用这些相同的对象来插入第三个副本,您可以再次运行查询(使用AsNoTracking())或分离对象(示例):

dbContext.Entry(person).State = EntityState.Detached;
person.ID = 0;
foreach (var address in person.Addresses)
{
  dbContext.Entry(address).State = EntityState.Detached;
  address.ID = 0;
}

this._context.Persons.Add(person);
this._context.SaveChanges();

答案 1 :(得分:9)

您需要对整个实体图进行正确的深层复制 - 最好的方法是将原始实体图序列化为内存流并将其反序列化为新实例。您的实体必须是可序列化的。它是often used with DataContractSerializer,但您也可以使用二进制序列化。

答案 2 :(得分:3)

C不是副本它是记录,你得到的错误是因为你试图更新它的主键,即使你不是它仍然无法工作。您需要创建一个新的X实体,然后从检索到的实体的属性中复制值,然后插入新实体。

答案 3 :(得分:1)

不确定它是否适用于4.1,来自http://www.codeproject.com/Tips/474296/Clone-an-Entity-in-Entity-Framework-4

public static T CopyEntity<T>(MyContext ctx, T entity, bool copyKeys = false) where T : EntityObject
{
    T clone = ctx.CreateObject<T>();
    PropertyInfo[] pis = entity.GetType().GetProperties();

    foreach (PropertyInfo pi in pis)
    {
        EdmScalarPropertyAttribute[] attrs = (EdmScalarPropertyAttribute[])pi.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false);

        foreach (EdmScalarPropertyAttribute attr in attrs)
        {
            if (!copyKeys && attr.EntityKeyProperty)
                continue;

            pi.SetValue(clone, pi.GetValue(entity, null), null);
        }
    }

    return clone;
}

您现在也可以将相关的entites复制到克隆对象;假设你有一个实体:Customer,它有导航属性:订单。然后,您可以使用上述方法复制客户及其订单:

Customer newCustomer = CopyEntity(myObjectContext, myCustomer, false);

foreach(Order order in myCustomer.Orders)
{
    Order newOrder = CopyEntity(myObjectContext, order, true);
    newCustomer.Orders.Add(newOrder);
}

答案 4 :(得分:1)

我使用Newtonsoft.Json,这个很棒的功能。

    private static T CloneJson<T>(T source)
    {
        return ReferenceEquals(source, null) ? default(T) : JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
    }