EntityFramework Core-копирование объекта и его размещение в базе данных
существует ли наилучшая практика для копирования сущности, внесения в нее некоторых изменений на основе пользовательского ввода, а затем повторной вставки в базу данных?
некоторые другие потоки Stackoverflow упоминали, что EF будет обрабатывать вставку новых объектов для вас, даже если тот же первичный ключ существует в базе данных, но я не совсем уверен, что это то, как EF Core обрабатывает его. Всякий раз, когда я пытаюсь скопировать объект, я получаю ошибку
Cannot insert explicit value for identity column in table when IDENTITY_INSERT is set to OFF
В основном мне просто нужна чистая способ копирования объекта, внести некоторые изменения в него на основе пользовательского ввода, а затем вставить эту копию обратно в базу данных и иметь автоматическое увеличение Id должным образом. Есть ли наилучшая практика или простой способ сделать это без необходимости вручную устанавливать свойства null или empty?
EDIT: пример кода для извлечения объекта из базы данных:
public Incident GetIncidentByIdForCloning(int id)
{
try
{
return _context.Incident.Single(i => i.IncidentId == id);
}
catch
{
return null;
}
}
код после извлечения объекта (так как некоторые поля автоматически генерируются как RowVersion, которая является Метки):
public IActionResult Clone([FromBody]Incident Incident)
{
var incidentToCopy = _incidentService.IncidentRepository.GetIncidentByIdForCloning(Incident.IncidentId);
incidentToCopy.IncidentTrackingRefId = _incidentService.IncidentRepository.GetNextIdForIncidentCategoryAndType(
Incident.IncidentCategoryLookupTableId, Incident.IncidentTypeLookupTableId).GetValueOrDefault(0);
incidentToCopy.RowVersion = null;
incidentToCopy.IncidentId = 0; //This will fail with or without this line, this was more of a test to see if manually setting would default the insert operation, such as creating a brand new object would normally do.
incidentToCopy.IncidentCategoryLookupTableId = Incident.IncidentCategoryLookupTableId;
incidentToCopy.IncidentTypeLookupTableId = Incident.IncidentTypeLookupTableId;
var newIncident = _incidentService.IncidentRepository.CreateIncident(incidentToCopy);
...
Я понимаю, что могу просто сделать совершенно новый объект и сделать левое копирование, но это кажется ужасно неэффективным, и я хочу знать, предлагает ли EF Core лучшие решения.
3 ответов
таким образом, я прошел через "возможный дубликат" поток немного больше, чем я сделал, когда я изначально наткнулся на него перед созданием этого, и было не так сильно загруженное решение, которое я пропустил, что по существу просто захватывает все значения сразу при извлечении объекта из базы данных-и он не получает ссылку на этот объект в процессе. Мой код теперь выглядит так:
try
{
var incidentToCopy = _context.Incident.Single(i => i.IncidentId == id);
return (Incident) _context.Entry(incidentToCopy).CurrentValues.ToObject();
}
в своем IncidentRepository
класс попробуйте получить Incident
С помощью AsNoTracking
и он должен отслеживаться как новый объект при его добавлении.
public void Clone(int id)
{
// Prevent tracking changes to the object.
var incident = _context.AsNoTracking().SingleOrDefault(i => i.Id == id);
// Setting back to 0 should treat the object Id as unset.
incident.Id = 0;
// Add the Incident while it is untracked will treat it as a new entity.
_context.Incidents.Add(incident);
_context.SaveChanges();
}
Я считаю, что здесь происходит следующее:
когда вы извлекаете значение из базы данных, оно сохраняется в чем-то вроде
context.ChangeTracker.Entries<Incident>
который представляет собой коллекцию отслеживаемых записей инцидентов. При изменении свойства id объекта инцидента, который вы получили, вы как бы злоупотребляете ChangeTracker во имя эффективности. ChangeTracker не считает, что вы создали новый объект. Вы могли бы попробовать что-то вроде поиска запись в ChangeTracker и установить его состояние отсоединен затем после того, как вы установили id 0 Добавить объект обратно в контекст.DbSet но в этот момент Вы, вероятно, сделали вещи более сложными, чем просто копирование объекта.