Entity Framework ObjectContext -> 原始SQL调用本地DBMS

4
我有一个使用ADO.NET实体框架的应用程序(VS2008版本,而不是更新、更酷的版本),我需要能够调用底层的DBMS(它是postgres)以调用一些实体框架不支持的SQL。
有没有办法从Entity Framework 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。
4个回答

17

虽然Craig的答案并没有直接奏效,但它让我找到了正确的方向。原来有一个EntityConnection.StoreConnection属性,可以获取到底层数据库管理系统的连接。因此,执行“本机”的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
        }
    }

然而,如果entityconnection处于事务中间,这将无法工作。 - Eamon Nerbonne
@Justin Grant 你好,我在想ExecuteSql是否使用了c相同的数据库连接?因为我希望它们在同一个事务中。谢谢。 - Joe.wang
1
2013年 EF 5 DbConnection conn = c.Database.Connection; - Nuri YILMAZ
1
另外,c.Database.SqlQueryc.Database.ExecuteSqlCommand - Mohamed Nuur

2

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


1
嗨 Craig - 我早先尝试过这个,但它不起作用,因为EntityConnection.CreateDbCommand创建一个只接受实体SQL的EntityCommand。但是...你的建议让我更仔细地查看了EntityConnection类,结果发现它有一个StoreConnection属性,这正是我要找的:连接到实际底层DBMS的连接。感谢您指引我正确的方向! - Justin Grant
是的,没错。感谢您的纠正。我会更新我的答案,包括您所写的内容。 - Craig Stuntz
顺便说一句,我认为你应该接受你自己的答案而不是这个;它比我的好。 - Craig Stuntz

0
根据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必须截断表并插入行)

希望对你有帮助。


好主意,但我不想因为客户端的限制而改变我的数据库架构。 - Justin Grant

0

谢谢Justin。我花了几个小时试图弄清楚为什么我的Entity Framework连接上没有StoreConnection属性....

对我来说关键的一点是,你必须将EF连接正式转换为System.Data.EntityClient.EntityConnection:

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

一旦我这样做了,其他一切都变得清晰明了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接