How to perform a transaction with an Entity Framework object context?
I created very a simple database using Entity Framework 4. I'd like to be able to use transactions on entities, but I can't seem to keep changes from rolling back. I really just need a way to abandon temporary changes to entities before they are saved to the database.
For example, the following code uses an entity framework object context "MusicContainer". Inside a TransactionScope, an Artist entity is created. The transaction then ends without being completed; so I'd expect the transaction to be rolled back. But, the program runs as if I'd never created the TransactionScope in the first place; after the TransactionScope ends, the line music.SaveChanges() saves the object to the database.
class Program
{
static void Main(string[] args)
{
using (MusicContainer music = new Music开发者_C百科Container())
{
using (TransactionScope transaction = new TransactionScope())
{
Artist artist = new Artist { Name = "Test" };
music.Artists.AddObject(artist);
}
// The transaction ended without Complete(); shouldn't the changes be abandoned?
music.SaveChanges();
}
}
}
If entity framework doesn't use TransactionScope the way I'm expecting it to here, how can I get the functionality I'm looking for? I have several circumstances where the caller of a function passes in the MusicContainer, and I need to leave the MusicContainer in a clean state before I return from the function (i.e. rolling back changes so they don't accidently get saved in with another SaveChanges called on the same MusicContainer object).
You don't need a TransactionScope
at all in this scenario, SaveChanges()
is all that's needed - if you have another using
block with MusicContainer
, this will be in a separate transaction and won't save any changes within your current using
block. TransactionScope
is only needed for transactions spanning multiple DB contexts.
In general a context should only be used for a unit of work consisting of related operations, once they are completed call SaveChanges()
. Open a new context for each separate, unrelated unit of work. Having said that, just use this in your scenario:
using (MusicContainer music = new MusicContainer())
{
Artist artist = new Artist { Name = "Test" };
music.Artists.AddObject(artist);
music.SaveChanges();
}
You have your SaveChanges in the wrong place.
class Program
{
static void Main(string[] args)
{
using (MusicContainer music = new MusicContainer())
{
using (TransactionScope transaction = new TransactionScope())
{
Artist artist = new Artist { Name = "Test" };
music.Artists.AddObject(artist);
music.SaveChanges();
}
// The transaction ended without Complete(); the changes are abandoned?
}
}
}
You shouldn't reuse your MusicContainer
if the transaction fails. Create a new one for each Unit of Work
Entity framework should be able to use TransactionScope. You need to start a New TransactionScope if you need to rollback the changes apllied only by this method.
using (MusicContainer music = new MusicContainer())
{
using (TransactionScope transaction = new TransactionScope(TransactionScopeOptions.RequiresNew))
{
Artist artist = new Artist { Name = "Test" };
music.Artists.AddObject(artist);
music.SaveChanges();
scope.Complete();
}
}
精彩评论