views:

1195

answers:

3

I have an app using the ADO.NET entity framework (the VS2008 version, not the newer, cooler one) and I need to be able to make a call down to the underlying DBMS (it's postgres) in order to call some SQL that Entity Framework doesn't support.

Is there a way to go from an Entity Framework ObjectContext to something that will let me execute raw SQL? (I need to run a TRUNCATE TABLE before inserting) I'm OK with a hacky solution (e.g. pull out the DBMS's connection string info from EF, and use that to create a connection using the postgres ADO.NET provider) but don't want to manage two sets of connection strings (one for entity framework, one for ADO.NET).

I'm aware of the limitatons of Entity Framework's first version, but it's not worth the investment required to switch this app to another ORM, and using EF 4.0 isn't an option either.

Any ideas?

BTW, this is the same question as http://stackoverflow.com/questions/915329/is-it-possible-to-run-native-sql-with-entity-framework, but the workaround described in that answer won't work for me since I really do need to execute raw SQL.

A: 

According to this post there is no support of DML in Entity Framework V1.

But there is support of stored procedures, but only such of them that return entities. That means if you create stored procedure in that way (sql server syntax):

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

You can't import it as function (actually you can, but it won't work - no code for this function will be generated)

I have found crutch solution to achive the goal: if you define sp as below:

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

 select top 1 * from t1
END

you can import as function and use it in your code like this:

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

(TruncateTable is the name of imported function)

I think there is another (better) solution. Other ways to digg are to tinker with .edmx file to make sp without return works or write another sp and map it to table insert function (that sp must truncate table and insert row)

I hope it will help you.

bniwredyc
good idea, but I don't want to have to change my DB schema just to work around a limitation on the client side.
Justin Grant
+2  A: 

Yes, you can do this. Look at EntityConnection.StoreConnection. You can get the connection out of the ObjectContext.

Craig Stuntz
Hi Craig - I tried this earlier and it doesn't work, because EntityConnection.CreateDbCommand creates an EntityCommand which only accepts Entity SQL. But... your suggestion led me to look more closely at the EntityConnection class, which turns out to have a StoreConnection property which is what I'm looking for: a connection to the actual underlying DBMS. Thanks for pointing me in the right direction!
Justin Grant
Yes, that's right. Thanks for the correction. I'll update my answer to include what you write.
Craig Stuntz
BTW, I think you should accept your answer instead of this one; it's better than mine.
Craig Stuntz
+3  A: 

Craig's answer, while it didn't work as-is, got me looking in the right direction. Turns out there's an EntityConnection.StoreConnection property which gets you a connection to the underlying DBMS. So executing "native" SQL is as easy as this:

    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