我正在尝试使用Entity Framework。我有以下代码抛出错误:
using (var db = new Entities.DB.DConn())
{
//...
foreach (Account account in accounts)
{
Entities.DB.Account dlAccount = new Entities.DB.Account();
dlAccount.GId = dlG.Id;
dlAccount.AccountName = account.NameAtFI;
dlAccount.AccountNumber = account.AcctNumber;
dlAccount.AcctType = account.AcctType;
dlAccount.AsOfDate = account.DateCreated;
dlAccount.IsDeleted = false;
dlAccount.DateModified = DateTime.UtcNow.ToUniversalTime();
db.Entry(dlAccount).State = ((dlAccount.GId == dlG.Id) ? EntityState.Modified : EntityState.Added);
db.SaveChanges();
}
}
例外:
存储更新,插入或删除语句会影响意外的行数(0)。自实体加载以来,实体可能已被修改或删除。
基本上我想要做的就是更新记录if dlAccount.GId == dlG.Id
或者如果它不存在则插入它。以下代码实现了我想要的而不使用EntityState:
using (var db = new Entities.DB.DConn())
{
//...
foreach (Account account in accounts)
{
bool isNewRecord = false;
Entities.DB.Account dlAccount = new Entities.DB.Account();
Entities.DB.Account exisitngAcct = db.Accounts.Where(x => x.GId == dlG.Id).FirstOrDefault(); //x.GId is NOT ad primary key
if (exisitngAcct != null)
{
dlAccount = exisitngAcct;
isNewRecord = true;
}
dlAccount.GId = dlG.Id;
dlAccount.AccountName = account.NameAtFI;
dlAccount.AccountNumber = account.AcctNumber;
dlAccount.AcctType = account.AcctType;
dlAccount.AsOfDate = account.DateCreated;
dlAccount.IsDeleted = false;
dlAccount.DateModified = DateTime.UtcNow.ToUniversalTime();
if (isNewRecord)
{
dldb.Accounts.Add(dlAccount);
}
db.SaveChanges();
}
}
任何人都可以看到我在这里做错的事吗?我真的很想让它工作,避免使用像上面那样膨胀的代码。
TIA
答案 0 :(得分:2)
首先我要指出你发布的(非EntityState)示例中的逻辑看起来并不像我期望的那样 - 至少基于我的理解,这可能是错误的:)
*免责声明 - 我已经在文本编辑器中将其破解,请原谅任何错误。
如果我们将此作为您的要求:
基本上我想要做的就是更新记录,如果dlAccount.GId == dlG.Id,或者如果它不存在则插入它。
然后我希望非EntityState版本看起来像这样:
using (var db = new Entities.DB.DConn())
{
//...
foreach (Account account in accounts)
{
Entities.DB.Account dlAccount = null;
Entities.DB.Account exisitngAcct = db.Accounts.Where(x => x.GId == dlG.Id).FirstOrDefault(); //x.GId is NOT ad primary key
if (exisitngAcct != null)
{
//If there is an EXISTING account, it will already be tracked by EF so no need to attach it.
dlAccount = exisitngAcct;
}
else
{
//No account exists, so we need to create one, and ADD it to our EF context as a new Entity
dlAccount = new Entities.DB.Account();
db.Accounts.Add(dlAccount);
}
dlAccount.GId = dlG.Id;
dlAccount.AccountName = account.NameAtFI;
dlAccount.AccountNumber = account.AcctNumber;
dlAccount.AcctType = account.AcctType;
dlAccount.AsOfDate = account.DateCreated;
dlAccount.IsDeleted = false;
dlAccount.DateModified = DateTime.UtcNow.ToUniversalTime();
db.SaveChanges();
}
}
假设您需要上述内容,并假设我们有充分的理由不按上述方式使用EF跟踪,那么手动处理EF状态将如下所示:
using (var db = new Entities.DB.DConn())
{
//...
foreach (Account account in accounts)
{
Entities.DB.Account exisitngAcct = db.Accounts.FirstOrDefault(x => x.GId == dlG.Id).FirstOrDefault(); //x.GId is NOT ad primary key
//NB. Since we're already pulling up the record with EF, there is *probably* no measurable advantage in not just using EF tracking at this point (unless this is a HUUUGE list of objects)
// in which case we should use the .AsNoTracking() modifier when we load the records (and they should be loaded in batches/all at once, to reduce DB hits)
Entities.DB.Account dlAccount = new Entities.DB.Account();
if(exisitngAcct == null)
{
db.Entry(dlAccount).State = EntityState.Added;
}
else
{
dlAccount.Id = exisitngAcct.Id; //We have to set the PK, so that EF knows which object to update
db.Entry(dlAccount).State = EntityState.Modified;
}
dlAccount.GId = dlG.Id;
dlAccount.AccountName = account.NameAtFI;
dlAccount.AccountNumber = account.AcctNumber;
dlAccount.AcctType = account.AcctType;
dlAccount.AsOfDate = account.DateCreated;
dlAccount.IsDeleted = false;
dlAccount.DateModified = DateTime.UtcNow.ToUniversalTime();
db.SaveChanges();
}
}