Клонирование данных в Entity Framework - PullRequest
51 голосов
/ 02 февраля 2010

Я создаю программное обеспечение, в котором пользователь может создавать новый продукт на основе более старого продукта.

Теперь мне нужно выполнить операции копирования / клонирования с помощью Entity Framework. Сначала я начал писать так:

foreach(sourcedata1 in table1)
{
   ... create new table
   ... copy data
   ... create Guid
   ... add
   foreach(sourcedata2 in table2)
   {
       ... create new table
       ... copy data
       ... create Guid
       ... add       

       ... and so on
   }
}

Проблема в том, что это не очень хороший способ сделать это. Есть ли какой-нибудь простой способ клонирования информации (кроме Guid, который необходимо сгенерировать для новых строк), или я должен все вручную скопировать?

Другое решение

Вы также можете использовать EmitMapper или AutoMapper для копирования свойств.

Ответы [ 6 ]

65 голосов
/ 30 июня 2010

Чтобы клонировать сущность в Entity Framework, вы можете просто отсоединить сущность от DataContext, а затем повторно добавить ее к EntityCollection.

context.Detach(entity);
entityCollection.Add(entity);

Обновление для EF6 + (из комментариев)

context.Entry(entity).State = EntityState.Detached;
entity.id = 0;
entity.property = value;
context.Entry(entity).State = EntityState.Added;
context.SaveChanges();
15 голосов
/ 10 февраля 2010

Используя прямую сериализацию, вы можете сделать это:

http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/a967b44b-c85c-4afd-a499-f6ff604e2139/

Используя Reflection, но с большим количеством кода вы можете сделать это: http://msmvps.com/blogs/matthieu/archive/2008/05/31/entity-cloner.aspx

10 голосов
/ 06 апреля 2011
public static EntityObject Clone(this EntityObject Entity)
{
    var Type = Entity.GetType();
    var Clone = Activator.CreateInstance(Type);

    foreach (var Property in Type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.SetProperty))
    {
        if (Property.PropertyType.IsGenericType && Property.PropertyType.GetGenericTypeDefinition() == typeof(EntityReference<>)) continue;
        if (Property.PropertyType.IsGenericType && Property.PropertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>)) continue;
        if (Property.PropertyType.IsSubclassOf(typeof(EntityObject)))  continue;

        if (Property.CanWrite)
        {
            Property.SetValue(Clone, Property.GetValue(Entity, null), null);
        }
    }

    return (EntityObject)Clone;
}

Это простой метод, который я написал. Это должно работать для большинства людей.

8 голосов
/ 09 июля 2014

Чтобы добавить новую строку, содержимое которой основано на существующей строке, выполните следующие действия:

  1. Получение объекта на основе начальной строки.
  2. Установка состояния входа длядобавленный объект.
  3. Изменить объект.
  4. Сохранить изменения.

Вот пример:

var rabbit = db.Rabbits.First(r => r.Name == "Hopper");
db.Entry(rabbit).State = EntityState.Added;
rabbit.IsFlop = false;
db.SaveChanges();
0 голосов
/ 26 января 2016

Очень короткий способ дублирования сущностей с использованием обобщений (VB, извините).
Он копирует значения внешнего ключа (внешние идентификаторы), но не загружает связанные с ними объекты.

<Extension> _
Public Function DuplicateEntity(Of T As {New, Class})(ctx As myContext, ent As T) As T
    Dim other As New T 'T is a proxy type, but New T creates a non proxy instance
    ctx.Entry(other).State = EntityState.Added 'attaches it to ctx
    ctx.Entry(other).CurrentValues.SetValues(ent) 'copies primitive properties
    Return other
End Function

Например:

newDad = ctx.DuplicateEntity(oDad)
newDad.RIDGrandpa ' int value copied
newDad.Grandpa    ' object for RIDGrandpa above, equals Nothing(null)
newDad.Children   ' nothing, empty

Я не знаю точно, как перезагрузить Grandpa в этом случае.
Это не работает:

ctx.SaveChanges()
ctx.Entry(newDad).Reload()

но на самом деле, нет проблем. Я бы лучше назначил Grandpa вручную, если мне это нужно.

newDad.Grandpa = oDad.Grandpa

EDIT: Как MattW предлагает в своем комментарии , отсоединяя и находя новую сущность, вы загружаете ее дочерние элементы (не коллекции).

ctx.Entry(newDad).State = EntityState.Detached
ctx.Find(newDad.RowId) 'you have to know the key name
0 голосов
/ 13 апреля 2015

Если вы хотите создать копию объекта для сравнения в дальнейшем при выполнении кода, вы можете выбрать объект в новом контексте БД.

Если, например, вы обновляете сущность, то позже в коде вы хотите сравнить обновленную и исходную сущность:

var db = new dbEntityContext();
var dbOrig = new dbEntityContext();

var myEntity = db.tblData.FirstOrDefault(t => t.Id == 123);
var myEntityOrig = dbOrig.tblData.FirstOrDefault(t => t.Id == 123);

//Update the entity with changes
myEntity.FirstName = "Gary";

//Save Changes
db.SaveChnages();

В этот момент myEntity.FirstName будет содержать "Gary", тогда как myEntityOrig.FirstName будет содержать исходное значение. Полезно, если у вас есть функция для регистрации изменений, где вы можете передать обновленную и оригинальную сущность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...