Transaction Scope Isolation level and EF6 - entity-framework

I am testing the EF6 isolation level but the test fails with:
Assert.AreEqual failed. Expected:<ReadUncommitted>. Actual:<Unspecified>.
The test:
public void TestIsolationLevelReadUncommitted()
{
// Arrange
using (
new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {IsolationLevel = IsolationLevel.ReadUncommitted}))
{
using (var context = new BoligEntities())
{
// Act
context.GetDbConnection().Open();
var isolationLevel = context.GetDbConnection().GetIsolationLevel();
// Assert
Assert.AreEqual(System.Data.IsolationLevel.ReadUncommitted, isolationLevel);
}
}
}
The test doesn't make much sense but I am wondering why it fails.

there is plenty of posts around transaction scope and EF.
Actually add uncommitted read and nolock to your searches.
Good basic explanation and example
FROM EF 6 on...
EF transaction scope docu
Generally you dont need it. ( there are exceptions)
and
i hope i dont have to support the system that uses uncommitted reads. ;-) Filthy...
good luck

Transaction is not the same as database. Looks like you are checking Isolation level for open connection but not for running transaction.
Generally speaking - you can open connection and run multiple transaction on this connection with different Isolation level.
using (var context = new MyEntities())
{
using (var tran = context.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
Assert.AreEqual(System.Data.IsolationLevel.ReadUncommitted, tran.UnderlyingTransaction.IsolationLevel);

Related

Entity Framework first Access to Database

Everytime when I open the database connection, the very first interaction with the database takes a lot of time. From the second interaction on the "speed" is much higher. I think it's an optimization of the Entity Framework and it looks like something good. But it's still the same even if I'm working with more than one database. The very first interaction with the first database is slow. But the first interaction with the second database is fast. Why isn't the first interaction with another database slow too? Another problem is that the Initializer only works with the first database. (I think this problem is caused by this optimization)
Related to this question (asked by myself):
Entity Framework 6 SetInitializer DbContext does not work for SQL Server Express and SQL Server Compact
Does anyone know how this optimization works and how to disable it? I don't actually work with the databases I compare them, for this case it would be nice to disable any optimization.
I'm wrote an answer as comment is not appropriate.
For the speed Yuliam pointed you to the good link.
For the rest, I'm not sure to understand your problem.
For me the following code (pertinent extract)
class Program {
static void Main(string[] args) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
String cs = #"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext ctx = new TestEFContext(cs)) {
Console.WriteLine(ctx.Orders.Count());
}
cs = #"Data Source=ALIASTVALK;Initial Catalog=TestEF2;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext ctx = new TestEFContext(cs)) {
Console.WriteLine(ctx.Orders.Count());
}
}
}
well create and recreate databases TestEF and TestEF2.
Did I misunderstand your question ?
===== Response to comment:
In this case both databases are always (re)created:
first run: creation
use SSMS to populate some data in some tables
second run
check tables content with SSMS : tables are empty <=> databases were recreated at second run.
Only trivial difference with your case: I use EF 6;

EntityFramework TransactionScope results in error if there's a call to asp.net security within its scope

I want to wrap some Entity Framework db I/o within a TransactionScope. In general it's working fine. But: I have some case that are basically like this:
using (var tx=new TransactionScope())
{
using (var cx=new MyDbcontext())
{
var myrecord=cx.somerecorord.find(someid);
if (Roles.IsUserInRole(username, "admin"))
DoAdminThing(myrecord);
else
DoNonAdminThing(myrecord);
cx.SaveChanges();
}
}
This blows up on Roles.IsUserInRole with "The provider did not return a ProviderManifestToken string."
It appears that it doesn't like to do the asp.net security db I/o within an EF TransactionScope. Is there any way around this?
I really really don't want to have to move the Roles stuff to before the transaction. That would require breaking functions that logically hang together into pieces.

Update issue with Generic Repositories using EF

I have created Generic Repository and I have two entities that i need to update in a transaction.
Here is what i m doing..
ProductOrganizationEntity poDataContext= new ProductOrganizationEntity();
IRepository<tblProductInfo> productRepo = new GenericRepository<ProductOrganizationEntity, tblConfirmation>(poDataContext);
Piece of Code which is causing problem is this.
using (TransactionScope txScope = new TransactionScope())
{
productRepo.Attach(productEntity);
productRepo.SaveChanges();
new ProductLocation().SaveLocation(productEntity.Locations, productEntity.productCode);
txScope.Complete();
}
productRepo.SaveChanges(); This is where it throws me Error. The error is
The operation could not be performed because OLE DB provider "SQLNCLI10" for linked server "Venus" was unable to begin a distributed transaction.
(We do have server named Venus but its not access in anyway in these transactions at all. Secondly as i said this works without transaction block).
This piece of code works fine if taken out from Transaction Block.
ProductLocation.SaveLocation is creating Repository for Location . Here is the code from Save Location.
IRepository<LocationInfo> locRepo= new GenericRepository<ProductOrganizationEntity, LocationInfo>(new ProductOrganizationEntity());
if (loc.locID <= 0) // This is a new Location to be added.
locRepo.Add(locEntity);
else
locRepo.Attach(siteToAdd);
locRepo.SaveChanges();
Here is what i have done in my generic repository for thse methods
public void Attach(TEntity entity)
{
if (entity == null)
throw new ArgumentException("Update : Supplied Entity is Null.");
_currentDbSet.Add(entity);
System.Data.Entity.Infrastructure.DbEntityEntry entry = _dataContext.Entry(entity);
entry.State = System.Data.EntityState.Modified;
}
and this is what i have in SaveChanges in my generic repo.
public virtual void SaveChanges()
{
if (_dataContext == null)
throw new Exception("SaveChanges: DataContext is not initialized.");
_dataContext.SaveChanges();
}
What is that i am doing wrong here .
I appreciate any pointers.
It might be possible that your server is linked to another SQL server at the database level.
Perhaps look at this: http://msdn.microsoft.com/en-us/library/ms188279.aspx
Must admit I've never used linked servers (not yet at least), but seeing "Linked Servers" in the error made me think of this.

Manage Transactions on Business Layer

I want to use TransactionScope class in my business layer to manage database operation in data access layer.
Here is my sample code. When i execute it, it tries to enable the dtc. I want to do the operation without enable dtc.
I already checked https://entlib.codeplex.com/discussions/32592 article. It didn't work for me. I read many articles on this subject but none of them really touch enterprise library or i didn't see.
by the way, i am able to use TransactionScope using dotnet sql client and it works pretty well.
what would be the inside of SampleInsert() method?
Thanks,
Business Layer method:
public void SampleInsert()
{
using (TransactionScope scope = new TransactionScope())
{
Sample1DAL dal1 = new Sample1DAL(null);
Sample2DAL dal2 = new Sample2DAL(null);
Sample3DAL dal3 = new Sample3DAL(null);
dal1.SampleInsert();
dal2.SampleInsert();
dal3.SampleInsert();
scope.Complete();
}
}
Data Access Layer method:
//sampleInsert method structurally same for each 3 dal
public void SampleInsert()
{
Database database = DatabaseFactory.CreateDatabase(Utility.DATABASE_INFO); ;
using (DbConnection conn = database.CreateConnection())
{
conn.Open();
DbCommand cmd = database.GetStoredProcCommand("P_TEST_INS", "some value3");
database.ExecuteNonQuery(cmd);
}
}
Hi yes this will enable dtc because you are creating 3 DB connections within one TransactionScope . When more than one DB connection is created within same TransactionScope the local transaction escalate to Distributed Transaction and hence dtc will be enabled to manage Distributed Trnsactions.You will have to do it in a way that only one DB connection is created for entire TransactionScope. I hope this will give you an idea.
After research and waching query analyzer, I changed the SampleInsert() body as follows and it worked. The problem was as ethicallogics mentioned opening new connection each time i access the database.
public void SampleInsert()
{
Database database = DatabaseFactory.CreateDatabase(Utility.DATABASE_INFO);
using (DbCommand cmd = database.GetStoredProcCommand("P_TEST_INS", "some value1"))
{
database.ExecuteNonQuery(cmd);
}
}

Managing transactions between EntityFramework and EnterpriseLibrary's DatabaseFactory

I'm working with an existing set of code that manages multiple database updates in a single transaction. Here is a simplified example:
Database db = DatabaseFactory.CreateDatabase();
using (DbConnection dbConnection = db.CreateConnection())
{
dbConnection.Open();
DbTransaction dbTransaction = dbConnection.BeginTransaction();
try
{
//do work
dbTransaction.Commit();
}
catch (Exception ex)
{
dbTransaction.Rollback();
}
}
I am also using EntityFramework in this same project for new development. Below is a simplified example of the usage of my repository class:
List<ThingViewModel> things = new List<ThingViewModel>();
// populate list of things
IObjectRepository thingRepository = new ThingRepository();
thingRepository.AddThings(things);
thingRepository.Save();
I want the work done in 'AddThings' to happen as part of the transaction in the first block of code.
Is there some clean way of blending my repository pattern into this existing code or vice-versa? I'm not at the point yet where it is feasible to rewrite the existing code to be entirely within EntityFramework, so I'm looking for some some interim approach.
I have tried passing the transaction from the older code into the repository, and thus EntityFramework, but that does not seem to work. I have also tried passing the ObjectContext back out to the older code in order to enlist it in the transaction. Neither approach works.
I cannot believe that I am the first person to encounter this hurdle in migrating existing code to EntityFramework... there must be something I am not considering.
I'll list the things that I have tried below:
using (TransactionScope transactionScope = new TransactionScope())
{
Database db = DatabaseFactory.CreateDatabase();
using (DbConnection dbConnection = db.CreateConnection())
{
dbConnection.Open();
DbTransaction dbTransaction = dbConnection.BeginTransaction();
try
{
//do work
dbTransaction.Commit();
}
catch (Exception ex)
{
dbTransaction.Rollback();
}
}
Thing thing = new Thing(){
Prop1 = Val1,
Prop2 = Val2
};
ThingObjectContext context = new ThingObjectContext();
context.Things.AddObject(thing);
context.SaveChanges();
transactionScope.Complete();
}
This last example 'works', it does not function as a transaction. When the EF insert fails, the EL commands are not rolled back by the TransactionScope. If I don't put those explicit calls to .Commit() and .SaveChanges(), nothing happens. I would really like for this to share the same connection if possible. Two other variations of this I am currently playing around with is trying to use the same connection between both EF and EL as well as use EnlistTransaction on one side or the other. Definitely trying to keep this from becoming a MSDTC - don't want the extra overhead associated with that.
Use TransactionScope instead of explicit transaction management. You'll simplify the overall code and everything you do should automatically detect and use the same transaction.
Is there any way you can call Database.GetOpenConnection() instead of CreateConnection() in your EL code, and pass in the things.Connection that you create inside of a TransactionScope block? I haven't tested this, but that is what I would try first.