使用Entity Framework插入/更新行的正确方法是什么?
我知道这三种方法:
1 - 使用Attach
var newSale = _context.ST_Sales.FirstOrDefault(x => x.SaleId == saleId);
newSale.Hours = 2;
_context.ST_Sales.Attach(newSale);
_context.ObjectStateManager.ChangeObjectState(newSale, EntityState.Modified);
_context.SaveChanges();
2 - 使用ApplyCurrentValues
var newSale = _context.ST_Sales.FirstOrDefault(x => x.SaleId == saleId);
newSale.Hours = 2;
_context.ST_Sales.ApplyCurrentValues(newSale);
_context.SaveChanges();
3 - 使用EF logic
var newSale = _context.ST_Sales.FirstOrDefault(x => x.SaleId == saleId);
newSale.Hours = 2;
_context.SaveChanges(); // EF tracks the newSale obj and knows that was changed
要插入,还有一种方法可以使用AddObject
var newSale = new ST_Sales();
newSale.Hours = 2;
_context.ST_Sales.AddObject(newSale);
_context.SaveChanges();
我遇到的问题是EF上的一个错误,说修改后的行仍在内存中。
我的方案:
我有一个简单的表关系:
tbl_Companies { CompanyId, Name }
tbl_Sales { CompanyId, Hours, Amount }
我的Edit View
简单获取本周的sales collection
为
var model = _context.ST_Sales.Where(x => x.CompanyId == 2);
return View(model);
并在HttpPost
操作上,我只需遍历每个操作并保存数据库更改,如
[HttpPost]
public ViewResult Index(List<ST_Sales> model)
和
bool newSale = false;
foreach( var s in model ) { // let's loop through all
newSale = false;
var sale = _context.ST_Sales.FirstOrDefault(x => x.SaleId == s.SaleId);
if( sale == null) {
// sale was not found, let's add it (this happens for todays date
// as there is no info yet in the db, but we need to add today's info)
sale = new ST_Sale();
sale.Company.Id = currentLoggedInUser.companyId;
newSale = true; // let's say it's a new sale so we can add the new object to the changes to commit
}
sale.Hours = s.Hours;
sale.Amount = s.Amount;
if( newSale ) {
// it's a new sale, let's add the obj to our Entity
_context.ST_Sales.AddObject(sale);
}
else {
// no need to do anything, EF is tracking the changes of existing objects
}
}
_context.SaveChanges();
这适用于一个用户...但如果我注销并使用其他用户登录,并且我可以在断点中看到companyId
值不同,很快我就会提交更改以保存我得到奇怪的错误:
IEntityChangeTracker的多个实例无法引用实体对象。
我做错了什么?
我正在Controller级别创建一个新实例,如:
public class SalesController : Controller
{
private SalesTrackerRepository db = SalesTrackerRepository.Instance;
...
}
并使用Sams Code
中的来源此外,我使用了Rick Strahl代码并最终使用:
public class SalesController : Controller
{
private SalesTrackerRepository db =
SalesTrackerRepositoryFactory.GetWebRequestScopedDataContext<SalesTrackerRepository>();
....
}
我一直得到同样的错误:(
我的测试基于Chrome和Opera使用不同凭据的同一台计算机。
如何在此类测试中出现此错误?
答案 0 :(得分:0)
应为每个请求创建并释放_context
,不再。多个并发请求不应共享上下文。
答案 1 :(得分:0)
我会尝试使用此帖子中的IDatabaseFactory:Entity Framework 4 CTP 4 / CTP 5 Generic Repository Pattern and Unit Testable以及IoC容器(Structuremap,Unity,Ninject)来根据Http请求确定DatabaseFactory实例化的范围。
代码应如下所示:
IDatabaseFactory.cs
public interface IDatabaseFactory : IDisposable
{
Database Get();
}
DatabaseFactory.cs
public class DatabaseFactory : Disposable, IDatabaseFactory {
private Database _database;
public Database Get() {
return _database ?? (_database = new Database());
}
protected override void DisposeCore() {
if (_database != null)
_database.Dispose();
}
}
一次性扩展方法:
<强> Disposable.cs 强>
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}
答案 2 :(得分:0)
得到了错误!
我正在使用MemoryCache
来缓存一些结果,并意识到我正在使用该缓存来请求EntityKey
。
我的建议:请检查您的项目中是否真的要处理所有这些变通办法!