是否有最佳做法来复制实体,根据用户输入对其进行一些更改,然后将其重新插入数据库?
其他一些Stackoverflow线程已经提到,即使数据库中存在相同的主键,EF也会为您处理插入新对象,但我不太确定EF Core是如何处理它的。每当我尝试复制一个对象时,我都会收到错误
Cannot insert explicit value for identity column in table when IDENTITY_INSERT is set to OFF
基本上我只需要一种简洁的方法来复制对象,根据用户输入对其进行一些更改,然后将该副本插回到数据库中,并使Id自动递增。是否有最佳实践或简单的方法,而无需手动将属性设置为null或为空?
编辑:从数据库中检索对象的示例代码:
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是否提供了更好的解决方案。
答案 0 :(得分:6)
所以我经历了“可能重复”的线程比我在创建这个之前最初偶然发现它时所做的更多,并且我忽略了一个不那么高度支持的解决方案,基本上只是抓住所有从数据库中检索对象时的值 - 它不会在进程中检索对该对象的引用。我的代码现在看起来像这样:
try
{
var incidentToCopy = _context.Incident.Single(i => i.IncidentId == id);
return (Incident) _context.Entry(incidentToCopy).CurrentValues.ToObject();
}
答案 1 :(得分:4)
在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();
}
答案 2 :(得分:0)
我相信这里发生的事情如下:
从数据库中检索值时,它会存储在
之类的内容中context.ChangeTracker.Entries<Incident>
正在跟踪的事件条目的集合。当您更改已检索到的事件对象的id属性时,您会在效率名称中滥用ChangeTracker。 ChangeTracker不相信您已创建新对象。您可以尝试在ChangeTracker中查找条目并将其设置为分离,然后在将id设置为0后将对象添加回context.DbSet,但此时您可以尝试可能比简单地复制对象更复杂。