Entity Framework 5 глубокое копирование / клонирование объекта
Я использую Entity Framework 5 (DBContext) и я пытаюсь найти лучший способ глубокого копирования сущности (т. е. скопировать сущность и все связанные объекты), а затем сохранить новые сущности в базе данных. Как я могу это сделать? Я изучил использование методов расширения, таких как CloneHelper но я не уверен, если это относится к DBContext.
3 ответов:
один дешевый простой способ клонирования сущность-это что-то вроде этого:
var originalEntity = Context.MySet.AsNoTracking() .FirstOrDefault(e => e.Id == 1); Context.MySet.Add(originalEntity); Context.SaveChanges();хитрость тут AsNoTracking() - когда вы загружаете такой объект, ваш контекст не знает об этом, и когда вы вызываете SaveChanges, он будет рассматривать его как новый объект.
если
MySetимеет ссылку наMyPropertyи вы хотите его копию тоже, просто используйтеInclude:var originalEntity = Context.MySet.Include("MyProperty") .AsNoTracking() .FirstOrDefault(e => e.Id == 1);
вот еще один вариант.
Я предпочитаю его в некоторых случаях, потому что он не требует выполнения запроса специально для получения данных для клонирования. Этот метод можно использовать для создания клонов сущностей, уже полученных из базы данных.
//Get entity to be cloned var source = Context.ExampleRows.FirstOrDefault(); //Create and add clone object to context before setting its values var clone = new ExampleRow(); Context.ExampleRows.Add(clone); //Copy values from source to clone var sourceValues = Context.Entry(source).CurrentValues; Context.Entry(clone).CurrentValues.SetValues(sourceValues); //Change values of the copied entity clone.ExampleProperty = "New Value"; //Insert clone with changes into database Context.SaveChanges();этот метод копирует текущие значения из источника в новую добавленную строку.
это универсальный метод расширения, который позволяет обычным клонированием.
вы должны принести
System.Linq.Dynamicот nuget.public TEntity Clone<TEntity>(this DbContext context, TEntity entity) where TEntity : class { var keyName = GetKeyName<TEntity>(); var keyValue = context.Entry(entity).Property(keyName).CurrentValue; var keyType = typeof(TEntity).GetProperty(keyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).PropertyType; var dbSet = context.Set<TEntity>(); var newEntity = dbSet .Where(keyName + " = @0", keyValue) .AsNoTracking() .Single(); context.Entry(newEntity).Property(keyName).CurrentValue = keyType.GetDefault(); context.Add(newEntity); return newEntity; }единственное, что вам нужно реализовать самостоятельно, это метод GetKeyName. Это может быть что угодно от
return typeof(TEntity).Name + "Id"доreturn the first guid propertyили вернуть первое свойство, помеченноеDatabaseGenerated(DatabaseGeneratedOption.Identity)].в моем случае я уже отметил свои классы с
[DataServiceKeyAttribute("EntityId")]private string GetKeyName<TEntity>() where TEntity : class { return ((DataServiceKeyAttribute)typeof(TEntity) .GetCustomAttributes(typeof(DataServiceKeyAttribute), true).First()) .KeyNames.Single(); }
Comments