我使用Entity Framework为项目创建原型,现在它正在工作,我想让程序准备好进行生产。
我面临EF的许多挑战,最大的一个是并发管理(它是一个财务软件)。
鉴于似乎没有办法处理与EF的悲观并发,我必须切换到SQL中的存储过程。
说实话,我有点害怕可能代表的工作量。
我想知道以前是否有人处于相同的情况,使用EF将.net代码转换为原始SQL的最佳策略是什么。
编辑: 我正在调查CLR,但目前尚不清楚悲观的可靠性是否可以用它来管理。在这种情况下,它是一个比TSQl更有趣的选项吗?如果我理解的话,这将允许我重用我的部分C#代码和调用另一个函数的函数结构。
答案 0 :(得分:1)
我在那里,好消息是如果你不愿意,你不必放弃实体框架。坏消息是你必须自己更新数据库。这并不像看起来那么难。我目前正在使用EF 5但计划进入EF 6.我不明白为什么这仍然不适用于EF 6。
首先在DbContext的构造函数中将其强制转换为IObjectContextAdapter并获取对ObjectContext的访问权限。我为这个
制作了一个属性public virtual ObjectContext ObjContext
{
get
{
return ((IObjectContextAdapter)this).ObjectContext;
}
}
一旦你订阅了SavingChanges事件 - 这不是我们的确切代码,有些东西会从其他方法复制出来并重做。这只是让您了解自己需要做什么。
ObjContext.SavingChanges += SaveData;
private void SaveData(object sender, EventArgs e)
{
var context = sender as ObjectContext;
if (context != null)
{
context.DetectChanges();
var tsql = new StringBuilder();
var dbParams = new List<KeyValuePair<string, object>>();
var deletedEntites = context.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted);
foreach (var delete in deletedEntites)
{
// Set state to unchanged - so entity framework will ignore
delete.ChangeState(EntityState.Unchanged);
// Method to generate tsql for deleting entities
DeleteData(delete, tsql, dbParams);
}
var addedEntites = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added);
foreach (var add in addedEntites)
{
// Set state to unchanged - so entity framework will ignore
add.ChangeState(EntityState.Unchanged);
// Method to generate tsql for added entities
AddData(add, tsql, dbParams);
}
var editedEntites = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach (var edit in editedEntites)
{
// Method to generate tsql for updating entities
UpdateEditData(edit, tsql, dbParams);
// Set state to unchanged - so entity framework will ignore
edit.ChangeState(EntityState.Unchanged);
}
if (!tsql.ToString().IsEmpty())
{
var dbcommand = Database.Connection.CreateCommand();
dbcommand.CommandText = tsql.ToString();
foreach (var dbParameter in dbParams)
{
var dbparam = dbcommand.CreateParameter();
dbparam.ParameterName = dbParameter.Key;
dbparam.Value = dbParameter.Value;
dbcommand.Parameters.Add(dbparam);
}
var results = dbcommand.ExecuteNonQuery();
}
}
}
为什么我们在更新后将实体设置为未修改,因为您可以执行
var changed properties = edit.GetModifiedProperties();
获取所有已更改属性的列表。由于所有实体现在都标记为未更改,因此EF不会向SQL发送任何更新。
您还需要弄乱元数据,从实体到表格,从属性到字段。这并不难,但弄乱元数据确实需要一些时间来学习。我有时还会挣扎的东西。我将所有内容重构为一个IMetaDataHelper接口,我在实体类型和属性名称中传递它以获取表和字段 - 以及缓存结果,因此我不必一直查询元数据。
最后,tsql是一个具有锁定提示并包含事务级别的所有T-SQL的批处理。如果用户将它们更新为2,我们也会将数字字段从刚设置为nfield = 10更改为nfield = nfield + 2,以避免出现并发问题。
一旦有人开始编辑您的实体,您将无法获得SQL锁定但我不知道您将如何通过存储过程获得该数据。
总而言之,我花了大约两天的时间才能为我们全力以赴。