【问题标题】:Entity Framework ObjectContext -> raw SQL calls to native DBMS实体框架 ObjectContext -> 对本机 DBMS 的原始 SQL 调用
【发布时间】:2009-10-16 01:50:50
【问题描述】:

我有一个使用 ADO.NET 实体框架(VS2008 版本,而不是更新、更酷的版本)的应用程序,我需要能够调用底层 DBMS(它是 postgres)才能调用一些实体框架不支持的 SQL。

有没有办法从实体框架 ObjectContext 转到可以让我执行原始 SQL 的东西? (我需要在插入之前运行 TRUNCATE TABLE)我可以使用 hacky 解决方案(例如,从 EF 中提取 DBMS 的连接字符串信息,并使用它来使用 postgres ADO.NET 提供程序创建连接)但不要想要管理两组连接字符串(一组用于实体框架,一组用于 ADO.NET)。

我知道 Entity Framework 的第一个版本的限制,但是不值得将此应用程序切换到另一个 ORM 所需的投资,并且使用 EF 4.0 也不是一种选择。

有什么想法吗?

顺便说一句,这与Is it possible to run native sql with entity framework? 的问题相同,但该答案中描述的解决方法对我不起作用,因为我确实需要执行原始 SQL。

【问题讨论】:

    标签: .net entity-framework postgresql ado.net


    【解决方案1】:

    克雷格的回答虽然没有按原样工作,但让我找到了正确的方向。原来有一个 EntityConnection.StoreConnection 属性可以让你连接到底层 DBMS。所以执行“原生”SQL 就这么简单:

        static void ExecuteSql(ObjectContext c, string sql)
        {
            var entityConnection = (System.Data.EntityClient.EntityConnection)c.Connection;
            DbConnection conn = entityConnection.StoreConnection;
    
            ConnectionState initialState = conn.State;
            try
            {
                if (initialState != ConnectionState.Open)
                    conn.Open();  // open connection if not already open
                using (DbCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = sql;
                    cmd.ExecuteNonQuery();
                }
            }
            finally
            {
                if (initialState != ConnectionState.Open)
                    conn.Close(); // only close connection if not initially open
            }
        }
    

    【讨论】:

    • 但是,如果实体连接处于事务的中间,这将不起作用。
    • @Justin Grant 嗨,我在想ExecuteSql 正在使用与c 相同的数据库连接?因为我希望他们在一次交易中。谢谢。
    • 2013 年 EF 5 DbConnection conn = c.Database.Connection;
    • 还有,c.Database.SqlQueryc.Database.ExecuteSqlCommand
    【解决方案2】:

    是的,您可以这样做。查看 EntityConnection.StoreConnection。您可以从 ObjectContext 中获取连接。

    【讨论】:

    • 嗨 Craig - 我之前尝试过,但它不起作用,因为 EntityConnection.CreateDbCommand 创建了一个仅接受 Entity SQL 的 EntityCommand。但是...您的建议使我更仔细地查看了 EntityConnection 类,结果证明它具有我正在寻找的 StoreConnection 属性:与实际底层 DBMS 的连接。感谢您为我指明正确的方向!
    • 是的,没错。感谢您的指正。我会更新我的答案以包括你写的内容。
    • 顺便说一句,我认为您应该接受您的答案而不是这个答案;比我的好。
    【解决方案3】:

    根据this post,Entity Framework V1 中不支持 DML。

    但支持存储过程,但仅支持返回实体的存储过程。这意味着如果您以这种方式创建存储过程(sql server 语法):

    CREATE PROCEDURE [dbo].[usp_trncate]
    AS
    BEGIN
     truncate table t1
    END
    

    你不能将它作为函数导入(实际上你可以,但它不起作用 - 不会生成此函数的代码)

    我找到了实现目标的拐杖解决方案:如果您将 sp 定义如下:

    CREATE PROCEDURE [dbo].[usp_trncate]
    AS
    BEGIN
     truncate table t1
    
     select top 1 * from t1
    END
    

    您可以将其作为函数导入并在您的代码中使用,如下所示:

    TestEntities context = new TestEntities();
    context.TruncateTable();
    

    (TruncateTable 是导入函数的名称)

    我认为还有另一种(更好的)解决方案。其他挖掘方法是修改 .edmx 文件以使 sp 不返回工作或编写另一个 sp 并将其映射到表插入函数(该 sp 必须截断表并插入行)

    希望对你有帮助。

    【讨论】:

    • 好主意,但我不想为了解决客户端的限制而更改我的数据库架构。
    【解决方案4】:

    谢谢贾斯汀。我花了几个小时试图弄清楚为什么我的实体框架连接上的 StoreConnection 属性不可用......

    对我而言,关键是您必须将 EF 连接正式转换为 System.Data.EntityClient.EntityConnection:

    var newConn = (System.Data.EntityClient.EntityConnection)db.Connection;

    一旦我这样做了,其他一切都变得有意义了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-25
      • 1970-01-01
      • 2020-06-29
      • 1970-01-01
      • 2015-06-16
      相关资源
      最近更新 更多