当我尝试插入/更新记录时,出现以下错误。
无法跟踪实体类型的实例,因为另一个实例 具有与{'Id'}相同的键值的值已经被跟踪。
下面是我的代码。在这里,我以1为增量创建/生成ID(主键)。在保存和更新时都遇到错误
public bool SaveDataCapDetails(List<TDataCapDetails> lstDataCapDetails)
{
bool IsSuccess = false;
using (var dbContextTransaction = _objContext.Database.BeginTransaction())
{
try
{
List<TDataCapDetails> lstDataCapDetailsRecords = null;
if (lstDataCapDetails.Where(x => x.Id == 0).Count() > 0)
{
lstDataCapDetailsRecords = new List<TDataCapDetails>();
lstDataCapDetailsRecords.InsertRange(0, lstDataCapDetails);
int? id = _objContext.TDataCapDetails.Max(x => (int?)x.Id);
id = id == null ? 0 : id;
foreach (var item in lstDataCapDetailsRecords.Where(x => x.Id == 0))
{
id = id + 1;
item.Id = (int)id;
}
_objContext.Entry(lstDataCapDetailsRecords).State = EntityState.Detached;
_objContext.AddRange(lstDataCapDetailsRecords);
_objContext.SaveChanges();
}
if (lstDataCapDetails.Where(x => x.Id > 0).Count() > 0)
{
lstDataCapDetailsRecords = new List<TDataCapDetails>();
lstDataCapDetailsRecords = lstDataCapDetails.Where(x => x.Id > 0).ToList();
_objContext.UpdateRange(lstDataCapDetailsRecords);
_objContext.SaveChanges();
}
dbContextTransaction.Commit();
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
throw ex;
}
}
return IsSuccess;
}
我从下面的业务层调用的上述方法
bool success = dal.SaveDataCapDetails(lstDataCapDetails)
我已经尝试过使用AsNoTracking和其他可用选项,但仍然无法解决此问题。
对此有任何帮助。
答案 0 :(得分:3)
如果您想同时拥有Primary-Key
和Identity-Incremental
的表格,则必须在设置Table
之后创建ForeignKey
,而必须将Identity-Incremental
设置为ForeignKey
。喜欢:
遇到此问题后,您的代码将更改为此:
public bool SaveDataCapDetails(List<TDataCapDetails> lstDataCapDetails)
{
bool IsSuccess = false;
using (var dbContextTransaction = _objContext.Database.BeginTransaction())
{
try
{
List<TDataCapDetails> lstDataCapDetailsRecords = null;
if (lstDataCapDetails.Where(x => x.Id == 0).Count() > 0)
{
lstDataCapDetailsRecords = new List<TDataCapDetails>();
_objContext.AddRange(lstDataCapDetailsRecords);
_objContext.SaveChanges();
}
if (lstDataCapDetails.Where(x => x.Id > 0).Count() > 0)
{
lstDataCapDetailsRecords = new List<TDataCapDetails>();
lstDataCapDetailsRecords = lstDataCapDetails.Where(x => x.Id > 0).ToList();
_objContext.UpdateRange(lstDataCapDetailsRecords);
_objContext.SaveChanges();
}
dbContextTransaction.Commit();
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
throw ex;
}
}
return IsSuccess;
}
答案 1 :(得分:2)
首先,很多人错过了这些检查,因此导致运行时异常。 因此,您始终应检查实体的状态:
context.YourEntities.Local.Any(e => e.Id == id);
或
context.ChangeTracker.Entries<YourEntity>().Any(e => e.Entity.Id == id);
要确保您的实体“可以安全使用” ,如果您想使用方便的方法,可以使用以下方法:
/// <summary>
/// Determines whether the specified entity key is attached is attached.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="key">The key.</param>
/// <returns>
/// <c>true</c> if the specified context is attached; otherwise, <c>false</c>.
/// </returns>
internal static bool IsAttached(this ObjectContext context, EntityKey key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
ObjectStateEntry entry;
if (context.ObjectStateManager.TryGetObjectStateEntry(key, out entry))
{
return (entry.State != EntityState.Detached);
}
return false;
}
然后:
if (!_objectContext.IsAttached(entity.EntityKey))
{
_objectContext.Attach(entity);
}
这将为您省去覆盖SaveChanges()
方法的麻烦,除非确实需要,否则在任何情况下都不建议这样做。
答案 2 :(得分:2)
我看到您对Add和Update实体使用相同的方法,我的第一个建议是单独的关注点,并为Add添加一个不同的方法,并在可能的情况下为Update选择另一个方法。
另一方面,不清楚记录列表“ lstDataCapDetails”是否包含所有新记录或新记录和现有记录的混合以进行更新,在第二种情况下,您的代码将给您错误,因为您可以尝试将ID分配给现有记录,或者您可以尝试更新全新的记录。
通过检查是否跟踪该实体并将其分离,然后附加修改后的实体并对其进行更新,可以解决该错误。
在这里您可以看到方法的修改版本:
waitpid()
答案 3 :(得分:0)
当您要跟踪对.and().addFilter(new UsernamePasswordAuthenticationFilter() {
@Override
protected String obtainPassword(HttpServletRequest request) {
String password = super.obtainPassword(request);
return null != password ? password.toLowerCase() : null;
}
})
所做的更改,而不是实际上将未跟踪的model
保留在model
中时,会发生此错误。我有一点建议,或者实际上是一种替代建议的方法,可以解决您的问题。
memory
将自动跟踪更改。但是您可以在EntityFramework
中Ovverride
SaveChanges()
。
DbContext