Does EF6 no longer join ambient transactions?
I have transactions flowing from higher level WCF services and I need my EF context to join, and honor, that transaction. I have verified that the transaction is flowing properly.
What I am finding is that if I rollback the higher-level transaction, the data still persists to SQL. I have tried wrapping a transactionscope closer to the call to context.SaveChanges() but that doesn't help. Locally, if I don't commit that transaction then the data doesn't persist.
Inside of my services, this used to be all I had to do:
using (var context = new DummyContext())
{
context.Set<DummyEFEntity>().Add(dummyEFEntity);
context.SaveChanges();
}
What changed and how do I make this work?
Edit* Days later and the best I can guess is that EF 6 is broken when it comes to joining the ambient transaction. In the debugger I can see the transaction propagating down the levels of WCF services, the Transaction identifiers look correct. But, EF is ignoring it - no idea why.
Thanks,
Will
Related
In Spring Ado there is a base class to do non-committing database actions.
This works in Test methods so that data sent into the DB under test conditions isn't committed.
While the test is running this data can be accessed. When the test finishes, the transaction rolls back.
Does EF Core 6 have such a feature? I'm hoping not to have to write a bunch of commits and then clear them out in all my tests.
I am aware setting up a mock Repo, etc. will also work. I am just wondering if EF Core might have the option directly to do non-committing actions on the DB?
I can work around by figuring out what FK tables to insert data, etc. to perform a test and then remove the data in a Test Cleanup method. For what I have to do it's not that hard to do it this way.
Thanks!
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 some design requirements that are not supported by Entity Framework, but are easily met by a simple SQL Query.
Essentially I need to do an insert that sets an Identity value.
Are there drawbacks to making a sproc that does my insert and then having EF call that sproc?
Are there caching concerns I need to be worried about? (Because I will be updating data "behind EF's back".)
Are there concurrency issues?
Anything else I need to be worried about?
If you don't keep around your db context, i.e. you dispose it after every unit of work this should work just fine (this covers most web scenarios) - unless you concurrently operate on the same table - if that is the case you might want to use a lock to synchronize the SQL and the EF queries or catch OptimisticConcurrencyException thrown by EF.
If you do keep a context around on the other hand make sure that you refresh it with RefreshMode.StoreWins.
Also see "Saving Changes and Managing Concurrency"
We have a lot of legacy code that uses our own data object. We are slowly trying to introduce EF. We need the ability to enlist EF into a transaction we already started using System.Data.SqlClient.SQLTransaction. EF of course uses System.Transaction.Transaction. Is this possible?
To make things more clear. We have code all over the place that does the following:
public sub DeleteEntity()
Dim InTransaction = ado.InTransaction
if not InTransaction then ado.BeginTran
...
<--want to use EF Here
...
if not InTransaction then ado.CommitTran
end sub
The DeleteEntity routine is not simple. It has a lot of logic. I want to use EF for just want thing in the middle of the code so i need to enlist it in the active transaction. I can't just use transaction scope because of how it is designed. DeleteEntity is called in lots of places and i don't want to visit every place that calls the routine. It more has to deal with System.Transaction.Transaction and SqlTransaction then it does EF itself.
Update: I tried:
context.connection.EnlistTransaction(Transaction.Current)
That doesn't work.
I may be wrong but have you considered using ObjectQuery instead of using to Linq to Entities for the Delete operation. Here is what I found on MSDN here
Promotion of a transaction to a DTC may occur when a connection is
closed and reopened within a single transaction. Because the Entity
Framework opens and closes the connection automatically, you should
consider manually opening and closing the connection to avoid
transaction promotion. For more information, see How to: Manually Open
the Connection from the Object Context.
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.