"转换"实体框架程序到原始SQL

时间:2014-04-19 22:32:11

标签: sql .net sql-server entity-framework stored-procedures

我使用Entity Framework为项目创建原型,现在它正在工作,我想让程序准备好进行生产。

我面临EF的许多挑战,最大的一个是并发管理(它是一个财务软件)。

鉴于似乎没有办法处理与EF的悲观并发,我必须切换到SQL中的存储过程。

说实话,我有点害怕可能代表的工作量。

我想知道以前是否有人处于相同的情况,使用EF将.net代码转换为原始SQL的最佳策略是什么。

编辑: 我正在调查CLR,但目前尚不清楚悲观的可靠性是否可以用它来管理。在这种情况下,它是一个比TSQl更有趣的选项吗?如果我理解的话,这将允许我重用我的部分C#代码和调用另一个函数的函数结构。

1 个答案:

答案 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锁定但我不知道您将如何通过存储过程获得该数据。

总而言之,我花了大约两天的时间才能为我们全力以赴。