How to insert data in trasaction using entity-framewrok-4?
I have a order object and it has other collection that i need to inset in database in transaction.
cOrder->
->lstOrderItems
-->lstDressing, lstTopping, lstspecialInstruction
->userDetails
->trasactionTblsdetails
Also opinion required:-
1) Is it good to maintain transaction at database level or entity framework level.
2) What should be coding style.
right now i am following it this way but as i can predict it would require a lot of code but want to know this is only the way it work or far better solution exist.
public static void SaveOrder()
{
using (EposWebOrderEntities Ctx = new EposWebOrderEntities())
{
using (TransactionScope scope = new TransactionScope())
{
// do something...
Ctx.order.SaveChanges();
// do something...
//foreach to save the order items to databaswe
Ctx.orderitems.SaveChanges();
// do something...
//foreach to save in dressing tbl
Ctx.dressing.SaveChanges();
//foreach to save in topping tbl
Ctx.topping.SaveChanges();
//foreach to save in dressing tbl
Ctx.dressing.SaveChanges();
//foreach to save in spinst tbl
Ctx.dressing.SaveChanges();
scope.Complete();
success = true;
}
}
}
Use it this way. Is sufficient in most scenarios.
public static void SaveOrder()
{
using (EposWebOrderEntities Ctx = new EposWebOrderEntities())
{
Ctx.Entry<Order>(order).State = EntityState.Added;
Ctx.Entry<Dressing>(dressing).State = EntityState.Added;
Ctx.SaveChanges();
}
}
http://msdn.microsoft.com/en-us/library/dn456843.aspx
In all versions of Entity Framework, whenever you execute SaveChanges() to insert, update or delete >on the database the framework will wrap that operation in a transaction. This transaction lasts >only long enough to execute the operation and then completes. When you execute another such >operation a new transaction is started.
Related
I have code that looks like the example below. There's an explicit transaction involved because of some database tomfoolery that needs to be done via a SP, and a save changes in the middle of it all. (Exception handling, rollbacks, etc.. omitted):
void OuterMethod(MyDatbase context)
{
using(var dbTrans = context.Database.BeginTransaction())
{
// some stuff, the save puts the data where the SP can see it
Stuff(context);
context.SaveChanges();
// now some SP stuff
context.Database.ExecuteSqlCommand(#"spFoo", params);
// more stuff
MoreStuff(context);
AlmostUnrelatedCode(context);
context.SaveChanges();
dbTrans.Commit();
}
}
Right now the method AlmostUnrelatedCode() -- which is only marginally related to the process above -- needs a nice, fast, disposable read-only context 99% of the time. I have a factory that will serve me up the right kind of context when I need it. The 1% of the time it's called from the middle of that block above.
MyDatabase localReadOnlyContext;
void AlmostUnrelatedCode(MyDatabase context)
{
if ( context.Database.CurrentTransaction != null )
{
// Must use the context passed or everything deadlocks :(
localReadOnlyContext = context;
disposeContextLater = false;
}
else
{
// I just want to do this all the time
localReadOnlyContext = _contextFactory.CreateReadOptimized();
disposeContextLater = true;
}
// Do many, many things with my read-optimized context...
// The Dispose() on the class will check for disposeContextLater
}
What I'd like to do is to get rid of that transaction check, and in fact not need to pass the outer context at all if I can help it.
What I've tried:
Just ignoring what's going on in the outer transaction and using the context I generate all the time. Problem: deadlocks.
Trying to get the outermost transaction into the EF context I create with the _contextFactory. Problem: EF context constructors don't allow you to pass an existing transaction; also Database.CurrentTransaction has no setter.
Pulling the whole transaction out into a TransactionScope that wraps everything up. Problem: the method OuterMethod passes in the context, and I don't have control of the caller.
What I can't try:
Dirty reads/nolock. AlmostUnrelatedCode() needs the data as written so far.
I'd rather not:
Just keep using the outer context while inside of AlmostUnrelatedCode. AlmostUnrelatedCode deals with a lot of data trees and that context gets fat and unhappy really fast. It pollutes its context with crap really fast, and I'd rather just dispose of it when I'm done.
you can prevent the deadlocks by using one connection for multiple contexts.
example
var efConnectionString = ConfigurationManager.ConnectionStrings["SomeEntities"].ConnectionString;
// note EntityConnection, not SqlConnection
using (var conn = new EntityConnection(efConnectionString)) {
// important to prevent escalation
await conn.OpenAsync();
using (var c1 = new SomeEntities(conn, contextOwnsConnection: false)) {
//Use some stored procedures etc.
count1 = await c1.SomeEntity1.CountAsync();
}
using (var c2 = new SomeEntities(conn, contextOwnsConnection: false)) {
//Use some stored procedures etc.
count2 = await c2.SomeEntity21.CountAsync();
}
}
in your case just get the connection from the context and reuse it
context.Database.Connection
Can't you separate things done in AlmostUnrelatedCode like this:
void AlmostUnrelatedCode()
{
var context = _contextFactory.CreateReadOptimized();
AlmostUnrelatedCode(context);
context.Dispose();
}
void AlmostUnrelatedCode(MyDatabase context)
{
// Do many, many things with context...
}
Now you can call AlmostUnrelatedCode(with param) from your OuterMethod. And maybe there is even more to be separated. Consider SOLID.
Will the below code rollback the changes if there are any exception while saving?
using (SampleEntities context = new SampleEntities())
{
//Code Omitted
context.EmpPercAdjustments.AddRange(pp);
context.SampleJobs.AddRange(sampleJobs);
context.SaveChanges();
}
Or
Do I need to use transaction?
using (SampleEntities context = new SampleEntities())
{
//Code Omitted
using (System.Data.Entity.DbContextTransaction tranc = context.Database.BeginTransaction( ))
{
try
{
context.EmpPercAdjustments.AddRange(pp);
context.SampleJobs.AddRange(sampleJobs);
context.SaveChanges();
tranc.Commit();
}
catch (Exception ee)
{
tranc.Rollback();
}
}
}
Are there any advantages of using one over the others?
Yes it will rollback correctly.
In this case, you do not need to run an explicit transaction, because there is one already created by Entity Framework.
Creating a transaction by calling context.Database.BeginTransaction() is good, if you want f.e. to get the Id of just inserted record, something like this:
using (SampleEntities context = new SampleEntities())
{
using (System.Data.Entity.DbContextTransaction trans = context.Database.BeginTransaction( ))
{
context.SampleJobs.Add(newJob);
context.SaveChanges();
var jobId = newJob.Id;
//do other things, then commit or rollback
trans.Commit();
}
}
In this case, after calling SaveChanges(), the changes made on context objects are applied (so you can read database generated Id of added object in your scope), but they still have to be commited or rolled back, because changes are only dirty written.
Defining an explicit transaction can also be useful, if you have multiple methods that can modify context objects, but you want to have a final say, if changes they made will be all commited or not.
I am using SaveChanges() method as given below:
objAdbContext of Database A
objBdbContext of Database B
Updating table of DB A as given below
public string SaveA()
{
//Some stuff
objAdbContext.SaveChanges();
string result=UpdateDatabaseB(some parameters)
//Some stuff
}
public string UpdateDatabaseB(some parameters)
{
//Some stuff
objBdbContext.SaveChanges();
return "Success";
}
This case Database B is not getting updated. Is it correct way of updating multiple databases?
Both are independent Databases and How to implement TransactionScope in this case?
Try this:
using (TransactionScope scope = new TransactionScope())
{
// Save changes but maintain context1 current state.
context1.SaveChanges(SaveOptions.DetectChangesBeforeSave);
// Save changes but maintain context2 current state.
context2.SaveChanges(SaveOptions.DetectChangesBeforeSave);
// Commit succeeded since we got here, then completes the transaction.
scope.Complete();
// Now it is safe to update context state.
context1.AcceptAllChanges();
context2.AcceptAllChanges();
}
This sample was taken from this blog post:
Managing Transactions with Entity Framework 4
It is well known that the database locks taken inside the transaction are released on the end of that transaction. So, in this code..
public static TransactionScope CreateTransactionScope()
{
return new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted });
}
Actually, in this one...
using (DataContext dataContext = new DataContext())
using (TransactionScope rootScope = CreateTransactionScope())
{
using (TransactionScope nested = CreateTransactionScope())
{
Ticket ticket = dataContext.ExecuteQuery<Ticket>(
"SELECT * FROM Tickets WITH (UPDLOCK) WHERE id={0}", ticketId).First();
nested.Complete();
}
// Will the lock be still ON here? Because I don't need him to be!
}
When exactly the row/page lock (UPDLOCK) will be released - after the disposing the nested transaction or the root one?
It will be released only after the root scope will exit the using block and will dispose.
The best way to learn this kind of stuff is by getting your hands dirty.
Create a simple database with table A and table B, each contains single column, name it "TimeStamp" and create simple console application that inserting timestamp (or any kind of value) and you can play with the transaction options and learn the behaviour.
Here is my the test case :
[Test, Explicit]
public void SaveDeleteSaveThrowsTest()
{
Produit produit = new Produit { Libelle = "Test" };
using (ISession session = this.SessionProvider.OpenSession())
{
session.FlushMode = FlushMode.Auto;
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(produit);
transaction.Commit();
}
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(produit);
transaction.Commit();
}
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(produit);
Assert.Throws(typeof(StaleStateException), transaction.Commit);
}
}
}
The Ids are generated by HiLo.
If I assign 0 to the Id of the entity before saving it the 2nd time it works in this simple case but doesn't work in more complex scenarios where I have a one to many relation (I get the exception "collection owner not associated with session" when trying to delete the parent entity).
Is there a way to make it work ? (save, delete the save again the same entity)
Don't you use lazy loading in many-to-* relationship?
The problem is you are at first loading the entity, the close session and try to manipulate with (already detached) entity. In such a case sub-entities are proxies attached to closed session. You have to tell NHibernate to re-initialize the proxies: for each sub-entity call NHibernateUtil.Initialize.
Try Merge instead of SaveOrUpdate. It looks up the record in the database (additional select before insert or update). Note that Merge has a return value which returns the persistent instance while the given instance is still transient. You may need to clean the session or create a new session to make it work.
Try calling Session.Save or Session.Lock on the deleted produit object.
However, you should reconsider your design to avoid this problem in the first place. I would keep track of ids to be deleted in a separate collection then perform the deletes when the transaction is committed.