[英]Error while insert/update records in asp.net core
當我嘗試插入/更新記錄時,我收到以下錯誤。
無法跟蹤實體類型的實例,因為已經跟蹤了具有相同的{Id'}鍵值的另一個實例。
下面是我的相同代碼。 在這里,我以1為增量創建/生成ID(主鍵)。我在Save&Update中收到錯誤
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和其他可用選項,但我仍然無法解決此問題。
對此有任何幫助表示贊賞。
如果您想要使用Primary-Key
和Identity-Incremental
的Table
,則必須在設置ForeignKey
之后創建Table
,您必須為該ForeignKey
設置Identity-Incremental
。 喜歡:
遇到此問題,您的代碼更改為:
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;
}
首先,很多人都缺少這些檢查,從而導致運行時異常。 所以你總是應該檢查你的實體的狀態:
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()
方法的麻煩,除非你真的需要,否則不建議這樣做。
我看到你使用相同的方法添加和更新實體,我的第一個建議是單獨的關注點,並為Add添加一個不同的方法,如果可能的話,另一個方法用於Update。
另一方面,目前尚不清楚記錄列表“lstDataCapDetails”是否可能包含所有新記錄或新記錄和現有記錄的混合更新,在第二種情況下,您的代碼會給您錯誤,因為您可能嘗試分配Id到現有記錄,或者您可以嘗試更新全新記錄。
通過檢查是否正在跟蹤實體並將其分離,然后附加修改后的實體並更新它,可以解決您可以克服的錯誤。
在這里,您可以看到方法的修改版本:
public bool SaveDataCapDetails(List<TDataCapDetails> lstDataCapDetails)
{
bool IsSuccess = false;
using (var dbContextTransaction = _objContext.Database.BeginTransaction())
{
try
{
int? id = _objContext.TDataCapDetails.Max(x => (int?)x.Id);
id = id == null ? 0 : id;
// entities with Id == 0 --> new entities
// you may need to check if Id == null as well (depends on your data model)
var entitiesToAdd = lstDataCapDetails.Where(x => x.Id == 0);
foreach(var entity in entitiesToAdd)
{
entity.Id = id++;
// new entities is not tracked, its state can be changed to Added
_objContext.Entry(entity).State = EntityState.Added;
}
// entities with Id > 0 is already exists in db and needs to be updated
var entitiesToUpdate = lstDataCapDetails.Where(x => x.Id > 0);
foreach (var entity in entitiesToUpdate)
{
// check if entity is being tracked
var local = _objContext.Set<TDataCapDetails>().Local.FirstOrDefault(x => x.Id.Equals(entity.Id));
// if entity is tracked detach it from context
if (local != null)
_objContext.Entry<TDataCapDetails>(local).State = EntityState.Detached;
// attach modified entity and change its state to modified
_objContext.Attach(entity).State = EntityState.Modified;
}
// optional: assign value for IsSuccess
IsSuccess = _objContext.SaveChanges() > 0;
dbContextTransaction.Commit();
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
throw ex;
}
}
return IsSuccess;
}
如果要跟蹤對model
所做的更改,而不是在memory
實際保留未跟蹤的model
,則會發生此錯誤。 我有一點建議或實際上是另一種建議方法來解決你的問題。
EntityFramework
將自動跟蹤更改。 但是你可以在你的DbContext
Ovverride
SaveChanges()
。
public override int SaveChanges()
{
foreach (var ent in ChangeTracker.Entries<Client>())
{
if (ent.State == EntityState.Modified)
{
// Get the changed values
var modifiedProps = ObjectStateManager.GetObjectStateEntry(ent.EntityKey).GetModifiedProperties();
var currentValues = ObjectStateManager.GetObjectStateEntry(ent.EntityKey).CurrentValues;
foreach (var propName in modifiedProps)
{
var newValue = currentValues[propName];
//log your changes
}
}
}
return base.SaveChanges();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.