Подтвердить что ты не робот

Скопировать объект структуры объекта

У меня есть класс 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 есть несколько свойств.

4b9b3361

Ответ 1

Вам нужно сделать правильную глубокую копию всего графа объектов - лучший способ - сериализовать исходный граф объекта в потоке памяти и десериализовать его на новый экземпляр. Ваша организация должна быть сериализована. часто используется с DataContractSerializer, но вы также можете использовать двоичную сериализацию.

Ответ 2

В , это безумно легко с 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();

Ответ 3

C не является копией, это запись, ошибка, которую вы получаете, заключается в том, что вы пытаетесь обновить ее первичный ключ, даже если вы не все равно не поработали. Вам нужно создать новый объект X, а затем скопировать значения из свойств получаемого объекта и затем вставить новый объект.

Ответ 4

Не уверен, работает ли он в 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;
}

Теперь вы можете скопировать связанные объекты на свой клонированный объект; скажем, у вас есть лицо: Клиент, у которого есть свойство навигации: Заказы. Затем вы можете скопировать Клиента и их Заказы с использованием вышеуказанного метода:

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

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

Ответ 5

Я использую Newtonsoft.Json и эту потрясающую функцию.

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