I have multiple web sites running on a server. These sites access a local database, and in the database, a call is made to a stored procedure on a linked server.
All the websites work fine, except one that is now running Entity Framework 6.1.1.
When the call is done, we get the error: The operation could not be performed because OLE DB provider "SQLNCLI10" for linked server "___" was unable to begin a distributed transaction.
The code running at that point is autogenerated using a .tt file...
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("procname", param1, param2, param3, param4);
As mentioned, this runs fine with older versions of EF. (This is not a problem with the configuration of MSDTC.)
On this page (Working with Transactions (EF6 Onwards)), it says:
Starting with EF6 Database.ExecuteSqlCommand() by default will wrap the command in a transaction if one was not already present. There are overloads of this method that allow you to override this behavior if you wish. Also in EF6 execution of stored procedures included in the model through APIs such as ObjectContext.ExecuteFunction() does the same (except that the default behavior cannot at the moment be overridden).
Am I stuck? Do I need to revert back to Entity Framework 5?
Related
I am developing an application in which the database is selected by the end user at runtime. The database can either be on a MS SQL server or an IBM DB2 server. I am currently using IBM DB2 10 Express-c on a windows server for testing. I am developing using Visual Studio 2013 C# and Entity Framework 6. I have installed the EntityFramework.IBM.DB2 Nuget package for the DB2 support. I am using reverse-engineer code-first against an existing SQL server database to generate my base code. The application works fine against a SQL Server database.
I am using System.Data.Common.DbProviderFactories.GetFactory to generate the provider.
System.Data.EntityClient.EntityConnectionStringBuilder connectString = new System.Data.EntityClient.EntityConnectionStringBuilder(a_Connection);
System.Data.Common.DbConnection conn = System.Data.Common.DbProviderFactories.GetFactory(connectString.Provider).CreateConnection();
conn.ConnectionString = connectString.ProviderConnectionString;
LB500Database = new LB402_TestContext(conn, true);
a_Connection is provider=IBM.Data.DB2;provider connection string="Database=LISTBILL;User ID=xxxx;Password=yyyy;Server=db210:50000"
and is being parsed correctly by the EntityConnectionStringBuilder.
I then try to access a table in the database with
LBData500.LB_System oneSystem;
System.Linq.IQueryable<LB_System> allSystem = LB500Database.LB_System.Where(g => g.DatabaseVersion == databaseVersion && g.CompanyID == companyID);
I get an invalid operation exception "Sequence contains no matching element" which means that no elements are returned. If I remove the Where so that all rows are returned (there is one in the table) and try to enumerate the result set using the VS debugger I see the message:
"The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe."
I am not using multi-threading. I am not inside the OnModelCreating.
Just changing the connect string to point to SQL server works fine, so I think my basic approach is sound. If I were getting some kind of error back from the server I would have something to go on. I can run the query from inside Visual Studio, so I have connectivity.
Any pointers would be appreciated.
UPDATE:
I turns out the EF objects were generated using EF5 and the EF6 runtime was being used. I regenerated the EF objects using EF6 reverse engineer code first. I can now connect to the database and get an error message:
"ERROR [42704] [IBM][DB2/NT64] SQL0204N \"DBO.LB_SYSTEM\" is an undefined name."
The schema in the DB2 database is the same as my userid (in this case, not always). I added the CurrentSchema=xxxx to the provide connection string, but EF is still passing dbo as the schema name.
Now I need a way to change the schema name at run time. I saw a link to codeplex EFModelAdapter (http://efmodeladapter.codeplex.com). So I may give that a try.
Update2 After looking through EFModelAdapter, I decided to take a different route. Since I only need database access and not schema management, I decided to go with Dapper (https://github.com/StackExchange/dapper-dot-net). This works great for what I need and allows me to change the schema name when accessing DB2 databases.
As per my Update 2, Entity Framework was a little overkill for what I needed. I switched to dapper https://github.com/StackExchange/dapper-dot-net and I am working fine against multiple DBMSs.
I am working on a very large application with over 100 modules, and almost 500 tables in the database. We are converting this application to WPF/WCF using Entity Framework 4.2 Code First. Our database is SQL Anywhere 11. Because of the size of the database, we are using an approach similar to Bounded DbContexts, as described here http://msdn.microsoft.com/en-us/magazine/jj883952.aspx by Julie Lerman.
Each of our modules creates its own DbContext, modeling only the subset of the database that it needs.
However, we have run into a serious problem with the way DbContexts are created. Our modules are not neatly self-contained, nor can they be. Some contain operations that are called from several other modules. And when they are, they need to participate in transactions started by the calling modules. (And for architectural reasons, DTC is not an option for us.) In our old ADO architecture, there was no problem passing an open connection from module to module in order to support transactions.
I've looked at various DbContext constructor overloads, and tried managing the transaction from EntityConnection vs. the StoreConnection, and as far as I can tell, there is no combination that allows ModuleA to begin a transaction, call a function in ModuleB, and have ModuleB's DbContext participate in the transaction.
It comes down to two simple things:
Case 1. If I construct DbContextB with DbContextA's EntityConnection, DbContextB is not built with its own model metadata; it reuses DbContextA's metadata. Since the Contexts have different collections of DbSets, all ModuleB's queries fail. (The entity type is not a part of the current context.)
Case 2. If I construct DbContextB with ModuleA's StoreConnection, DbContextB does not recognize the StoreConnection's open transaction at the EntityConnection level, so EF tries to start a new transaction when ModuleB calls SaveChanges(). Since the database connection in fact has an open transaction, this generates a database exception. (Connection does not support parallel transactions.)
Is there any way to 1) force DbContextB to build its own model in Case 1, or 2) get DbContextB's ObjectContext to respect its StoreConnection's transaction state in Case 2?
(By the way, I saw some encouraging things in the EF6 alpha, but after testing it out, found the only difference was that I could create DbContextB on an open connection. But even then, the above 2 problems still exist.)
I suggest you try use the TransactionScope object to manage this task for you. As long as all of your DbContexts use the same connection string (not connection object) the transaction should not try to enlist MS-DTC.
I have one app that uses EnterpriseLibrary and Unity, and uses TransactionScope in just one place. This works nicely, despite the fact that it runs against SQL Server 2005:
// Execute a stored proc using a DbDatabase object inserted by Unity
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
// Update something using the same DbDatabase object
// Run the stored proc above, again
// Assert that the results are different than from the previous call.
}
Yes, this deliberately ends without a scope.Complete(): the example is from a test.
I also have another application just beginning. It uses Entity Framework 4.1. It accesses the same database on the same server. I attempted to use TransactionScope, with the same "make change, verify change, roll back change" idea in mind.
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
using(ProjectEntities db = new ProjectEntities())
{
Assert.IsFalse(db.tblEntities.Any(e=>e.X == desired_value));
db.tblEntities.Add(new tblEntity() { X = desired_value });
db.SaveChanges();
Assert.IsTrue(db.tblEntities.Any(e=> e.X == desired_value));
}
}
This fails with the very familiar error about MSDTC not being enabled for network access.
Right now, this minute, the first test in the first project succeeds, the second test fails.
So I have two questions:
Is there a way to rejigger my second test that would keep the transaction from escalating to MSDTC?
Anybody know why I'm getting different results from the two frameworks? Does EntLib keep a single connection allocated and open during the whole time it's used? Does EF do the opposite?
I have made many test regarding EF, EntLib DAAB, and TransactionScope.
There are several points you must take into account.
SQL Server Version
Connection String
EF and EntLib version
I don't remember the other combinations, but with SQL Server 2008 or later, EF5, and Entlib 5, you can enroll several DbContexts and DAAB operations in the same TransactionScope without scalating to MSDTC. But there's a very tricky part:
the connection string must include: MultipleActiveResultSets=true;
the connection string must have the exact format used by EF
The second part is the most confusing: when you use a connection string to EF, it will chaneg its format, but EntLib uses it as is in the connection string of the config file. So, what you have to do is debug the code, and note down the modified version of the connection string used by EF. You can find it in ctx.Database.Connection.ConnectionString, where ctx is the DbContext you're using. Once you've done so, just copy and paste the modified version of your connection string to your config file, and both EF and EntLib will use the same connection string, thus not escalating to MSDTC.
For previous versions of SQL Server (and sometimes depending on EF version) you can find different problems, but this guidelines can help you test your exact setup.
I don't know about the EnterpriseLibrary but EF does create and open new connection for every query and I think this is why you see those different results.
You can verify this by opening two DbConnections by hand.
I have created several custom activities that update tables in my DB (in this case SQL Server Compact), using Entity Framework 4 with POCOs.
If I put more than one of these inside a WF4 TransactionScope activity, I'm running into problems: EF disposes the DB connection after the first activity has finished, and when the next DB activity tries to do a DB update a new connection is built up. At this moment an exception is thrown.
System.Activities.WorkflowApplicationAbortedException : The workflow has been aborted.
----> System.Data.EntityException : The underlying provider failed on Open.
----> System.InvalidOperationException : The connection object can not be enlisted in transaction scope.
Do I have to keep the EF connection open during the whole transaction scope? How can I do that? Create an explicit custom activity for that, or is there a standard way?
My current workaround goes like this: I created a new code activity that creates our ObjectContext and explicitely calls dbContext.Connection.Open(). It returns the ObjectContext, which is then saved in a workflow variable. That one is passed to all the DB related activities as an InArgument<>. Inside my DB activities, I use this ObjectContext if it is passed in, otherwise I create a new one.
This does work, but I'm not satisfied with this solution: It needs the new InArgument for every DB related activity. In the workflow designer, I have to insert that special OpenDatabaseConnection activity inside the transaction scope, and then make sure that the correct variable is passed into all DB activities. This seems to be very inelegant and error prone, especially if other team members have to use these DB activities.
What would be a better way to handle this?
The problem is that when you open a second connection in the same transaction scope, an attempt is made to promote the transaction to a distributed transaction (even though there's nothing distributed about it since you connect to the same database). SQL Server CE doesn't support this scenario.
What I would do is create a custom 'container' activity that opens (and closes) the connection and makes it available to child activities. This is still not optimal but at least you no longer need to pass InArgument's around. You get the following activity tree:
TransactionScope
InitializeConnection
Sequence
CustomDataActivity1
CustomDataActivity2
CustomDataActivity3
InitializeConnection is a NativeActivity that uses NativeActivityContext.Properties to expose the connection (or the ObjectContext) to child activities.
Make sure you implement proper error handling to ensure you close the connection at all times.
NOTE: Distributed transactions are supported by the full SQL Server only through a Windows service called MSDTC (Microsoft Distributed Transaction Coordinator). You can find this one in your 'Local Services'. Since SQL Server CE is a database that should be able to operate completely standalone, it makes sense that it has no dependency on MSDTC. Therefore it has no support for distributed transactions.
This problem is not readily reproducible in a simple example here but was wondering if anyone has any experience and tips, here is the issue:
using Entity Framework
have many points in application where (1) data is written to some entity table e.g. Customer, (2) data is written to history table
both of these actions use Entity Framework, HOWEVER, they use different contexts
these actions need to be both in one transaction: i.e. if one fails to write, the other should not write, etc.
I can wrap them with a TransactionScope,
like this:
using (TransactionScope txScope = new TransactionScope()) {
...
}
but this gives me:
Microsoft Distributed Transaction Coordinator (MSDTC) is disabled for
network transactions.
Our database admin has told me that MSDTC is disabled by choice and can not be installed.
Hence I am making changes trying to create my own EntityConnection with a MetadataWorkspace with the idea that each context will use the same EntityConnection. However, this is proving near impossible trying to get it to work, e.g. currently I continue to get the above error even though theoretically both contexts are using EntityConnection. It's difficult to understand where/why Entity Framework is requiring the MSDTC for example.
Has anyone gone down this road before, have experience or code examples to share?
Well, the problem is quite easy.
If you are using sql server 2008 you should not have that problem because you have promotable transaction, and as .NET knows that you are using the same persistence store (the database) it wont promote it to DTC and commit it as local. look into promotable transaction with sql server 2008.
As far as I know Oracle is working in its driver to support promotable transactions, but I do not know the state, MS oracle driver does not support it.
http://www.oracle.com/technology/tech/windows/odpnet/col/odp.net_11.1.0.7.20_twp.pdf
If you are using a driver that do not support promotable transactions it is impossible for .NET to use local transaction doing two connections. You should change your architecture or convince the database admin for installing MSDTC.
I had a similar problem with SQL 2008, Entity Framework.
I had two frameworks defined (EF1, and EF2) but using identical connection strings to a sql 2008 database.
I got the MSDTC error above, when using nested "usings" across both.
eg the code was like this:
using (TransactionScope dbContext = new TransactionScope())
{
using (EF1 context = new EF1())
{
// do some EF1 db call
using (EF2 context2 = new EF2())
{
// do some EF2 db call
}
}
dbContext.Complete();
}
It wasnt as simple as this, because it was split across several methods, but this was the basic structure of "usings".
The fix was to only open one using at a time. No MTDSC error, No need to open distributed transactions on db.
using (TransactionScope dbContext = new TransactionScope())
{
using (EF1 context = new EF1())
{
// do some EF1 db call
}
using (EF2 context2 = new EF2())
{
// do some EF2 db call
}
dbContext.Complete();
}
I think that what you need to do is to force your contexts to share single database connection. You will be able then to perform these two operations against two different contexts in single transaction. You can achieve this by passing one EntityConnection object to both of your context's constructors. Of course this approach will require you to pass this object to methods which update DB.
I have recently blogged about creating database context scope which will make using multiple EF contexts and transactions easier.