unit of work - I don't need to use transactions? - c#

If I use Microsoft implementation unit of work from this tutorial:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
public class UnitOfWork : IDisposable
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private GenericRepository<Course> courseRepository;
public GenericRepository<Department> DepartmentRepository
{
get
{
if (this.departmentRepository == null)
{
this.departmentRepository = new GenericRepository<Department>(context);
}
return departmentRepository;
}
}
public GenericRepository<Course> CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new GenericRepository<Course>(context);
}
return courseRepository;
}
}
public void Save()
{
context.SaveChanges();
}
//......
}
I don't need to use transactions when I must add related items? For example when I must add order and order positions to database I don't need to start transaction because if something will go wrong then method Save() won't execute yes? Am I right?
_unitOfWork.OrdersRepository.Insert(order);
_unitOfWork.OrderPositionsRepository.Insert(orderPosition);
_unitOfWork.Save();
??

SaveChanges itself is transactional. Nothing happens at the database level when you call Insert, which based on the tutorial merely calls Add on the DbSet. Only once SaveChanges is called on the context does the database get hit and everything that happened up to that point is sent in one transaction.

You need transactions if you have multiple save changes in one method ... or chain of method calls using the same context.
Then you can roll back over the multiple save changes when your final update fails.
An example would be multiple repositories wrapping crud for an entity under the unit of work (IE a generic class). You may have many functions inserting and saving in each repository. However at the end you may find an issue which causes you to roll back previous saves.
EG in a service layer that needs to hit many repositories and execute a complex operation.

Related

ASP MVC Entity Framework Database context and classes

In my asp mvc Framework project, using EF, I have some objects (from classes) whose fields store data coming from my database.
My question is :
How to populate these fields, or manage methods of these objects using a dbcontext variable ?
Sol 1: Is it better to use each time I need a connection with db in my classes with the instruction (using (resource), see below ) ?
Sol 2: Is it betterI to code a singleton class to use one instance of the context ?
Sol 3: Or should I use another way for the links beetween my classes and the database ?
What is the best method considering performances and code quality.
Thanks for your attention .
Solution 1
public class Test
{
private T1 a;
private T2 b;
public Test()
{}
public void CreateFrom (int id)
{
using (var db=new WebApplicationMVCTest.Models.dbCtx())
{
a=db.T1s.Find(id);
b= db.T2s.Find(a.id2);
}
}
Solution 2:
public class DbSingleton
{
private static dbCtx instance;
private int foo;
private DbSingleton ()
{}
public static dbCtx Current
{
get
{
if (instance == null)
{
instance = new dbCtx();
}
return instance;
}
}
public static void Set (dbCtx x)
{
if (instance==null)
{
instance = x;
}
}
}
For a web project, never use a static DbContext. EF DbContexts are not thread safe so handling multiple requests will lead to exceptions.
A DbContext's lifespan should only be as long as it is needed. Outside of the first time setup cost when a DbContext is used for the first time, instantiating DbContexts is fast.
My advice is to start simple:
public ActionResult Create(/* details */)
{
using (var context = new AppDbContext())
{
// do stuff.
}
}
When you progress to a point where you learn about, and want to start implementing dependency injection applications then the DbContext can be injected into your controller / service constructors. Again, from the IoC container managing the DbContext, the lifetime scope of the Context should be set to PerWebRequest or equivalent.
private readonly AppDbContext _context;
public MyController(AppDbContext context)
{
_context = context ?? throw new ArgumentNullException("context");
}
public ActionResult Create(/* details */)
{
// do stuff with _context.
}
The gold standard for enabling unit testing would be injecting a Unit of Work pattern and considering something like the Repository pattern to make your dependencies easier to unit test.
The best advice I can give you starting out with EF and MVC is to avoid the temptation to pass Entities between the controller (server) and the UI. (views) You will come across dozens of examples doing just this, but it is a poor choice for performance, it also hides a LOT of land mines and booby traps for both performance, exceptions, and data security issues. The most important detail is that when the UI calls the controller passing what you expect will be an entity, you are not actually getting an entity, but a de-serialized JSON object cast to an entity. It is not an entity that is tracked by the DbContext handling the request. Instead, get accustomed to passing view models (serializable data containers with the data the view needs or can provide) and IDs + values where the controller will re-load entities to update the data only as needed.

multiple repositories sharing same context calling savechanges operation

I have a Web API architecture in following way:
Controller -> Services -> Repositories
Dependency is injected into using Unity framework via constructor injection pattern.
i have something similar in my project:
public class OrderService : IOrderService
{
private readonly IOrderRepo _orderRepo;
private readonly IProductRepo _prodRepo;
public OrderService(IOrderRepo orderRepo, IProductRepo prodRepo)
{
_orderRepo = orderRepo;
_prodRepo = prodRepo;
}
public void DoSomething()
{
_orderRepo.Update();
_prodRepo.Insert();
}
}
public class OrderRepo : IOrderRepo
{
private readonly CreditPortalContext _context;
public OrderRepo(MyContext context)
{
_context = context;
}
public void Update()
{
//Do something
_context.SaveChanges();
}
}
public class ProductRepo : IProductRepo
{
private readonly CreditPortalContext _context;
public ProductRepo(MyContext context)
{
_context = context;
}
public void Insert()
{
//Do something
_context.SaveChanges();
}
}
Now, OrderService is calling two different repository method to perform some database operation.
What I want is if something fails in _prodRepo.Insert(); method, it should rollback _orderRepo.Update(); call as well.
I am too far in this project so can not perform major architecture change at this point. Also, the context object is getting instantiated only once.(using Unity HierarchicalLifetimeManager)
Is there anyway i can achieve this?
this is not an ideal situation at all and I am afraid you're going to have to be quite creative.
You can't really rollback a statement that has already been committed, but you can do something else else.
So the situation is like this : you have 2 calls, call A and call B.
call A commits successfully. call B fails and you want to rollback A.
My suggestion is to perform the first commit to a different table.
Create a copy of your table in the database and commit your data there. if B succeeds then you issue another command to transfer the data to the main table where it should be. If B fails then you simply remove the data from the second table and your main table remains untouched.
This can be done via a stored procedure maybe, that you can call, give it the id of the record and then it does an update on the main table using the row from the second table. You can easily call a stored procedure from entity framework so that part should not be a problem.
So bottom line, use a temporary storage place and only move the data when your second call succeeds

In a long set of calculations, how can I avoid "The instance of entity type 'Person' cannot be tracked ..."

I am working on a console application that will execute a single transaction comprised of a complex set of business logic. There will be multiple services called during this transaction and it is almost certain that any given entity will be updated in the repository multiple times.
I am using dependency injection to inject my repositories, services, dbcontext, and unit of work wherever they are needed. In its very early stage, the transaction looks like this:
using (var scope = serviceProvider.CreateScope())
{
var dbContext = scope.ServiceProvider
.GetRequiredService<FantasySimulationDBContext>();
using (var dbContextTransaction =
dbContext.Database.BeginTransaction())
{
try
{
var flowControllerService =
scope.ServiceProvider.GetService<IFlowControllerService>();
flowControllerService.IncrementTime();
flowControllerService.IncrementTime();
dbContextTransaction.Commit();
}
catch (Exception e)
{
dbContextTransaction.Rollback();
}
}
}
I only call flowControllerService.IncrementTime() twice to illustrate the type of functionality I want to have. I want this to be a possibility, and it currently is not.
The IncrementTime method in my service looks like this:
public void IncrementTime()
{
//do a bunch of stuff to a "Person" object
_personRepository.UpdatePerson(person);
_unitOfWork.Complete();
}
The PersonRepository maps my domain models back to persistence models and updates them in the dbContext. It looks like this:
public class PersonRepository: IPersonRepository
{
private readonly FantasySimulationDBContext _dbContext;
private IMapper _mapper;
public PersonRepository(FantasySimulationDBContext context, IMapper mapper)
{
_dbContext = context;
_mapper = mapper;
}
...
public void UpdatePerson(Person person)
{
var mappedPerson = _mapper.Map<PersistenceModels.Person>(person);
_dbContext.People.Update(mappedPerson);
}
}
What ends up happening is the first call to IncrementTime works fine. However, the second call causes the following exception to occur: "The instance of entity type 'Person' cannot be tracked because another instance of this type with the same key is already being tracked." I know it is happening because when I save the first time, the "Person" that I saved is still in the dbContext's changetracker, and then I'm re-using the same dbContext in the second call to IncrementTime. So when the person repository tries to update the same person a second time, I get the exception because it's already in the change tracker.
I could detach everything each time after I commit the unit of work, but I never see that in anyone else's code, so I'm assuming I just have some fundamental aspect of my entire process wrong. So what is the correct way to handle the problem, or barring that, what misstep have I taken in designing this?
There are basically two ways to do this from what I can tell (other than the ways you've said: detach, etc). First is you can hold onto the entity and update that instead of the 'DTO' you are using. The other would be to fetch the instance of the Person like this:
var personModel = _dbContext.People.Find(person.ID);
_mapper.Map(person, personModel);
_dbContext.SaveChanges();
That way you are always just using the single instance that your DBContext is already holding onto and tracking.

How to get visibility to inserted records where DbContext is not saved yet

I am implementing a service layer where I need to make sure that certain number of operations across multiple tables happen in a transaction. Here is the work flow.
I get an instance of HistoricalData object that need to be stored in HistoricalData table. This is accomplished in AddHistoricalData method.
I need to retrieve all records from HistoricalData table that include what’s inserted in #1 but can have more records. This is done in ProcessAllData method.
After processing all those records, the results are stored in two other tables, ProcessStatus and ProcessResults. If anything goes wrong, I need to rollback transaction include what’s inserted in operation #1.
This is how its implemented.
public class HistoricalDataService : IHistoricalDataService
{
private MyDbContext dbContext;
public HistoricalDataService(MyDbContext context)
{
this.dbContext = context;
}
void AddHistoricalData(HistoricalData hData)
{
// insert into HistoricalData table
}
void ProcessAllData()
{
// Here we process all records from HistoricalData table insert porcessing results into two other tables
}
void SaveData()
{
this.dbContext.SaveChanges();
}
}
Here is how this class methods are been called.
HistoricalDataService service = new HistoricalDataService (dbcontext);
service.AddHistoricalData(HistoricalData instance);
service.ProcessAllData();
service.SaveData();
Problem with this approach is that whatever is inserted in HistoricalData table during call to AddHistoricalData method is not visible in the ProcessAllData call, because dbContext.SaveChanges is called only at the end. I am thinking that I need to somehow bring transaction scope in here but not sure how to expose a function where that transaction scope should be started?
There are different ways you can do this. Try this (untested, but POC)
public class HistoricalDataService : IHistoricalDataService
{
private DbContext dbContext;
private DbContextTransaction dbContextTransaction;
public HistoricalDataService(DbContext context)
{
this.dbContext = context;
}
void AddHistoricalData(HistoricalData hData)
{
if (dbContext.Database.CurrentTransaction == null)
{
dbContextTransaction = dbContext.Database.BeginTransaction();
}
// insert into HistoricalData table
dbContext.SaveChanges();
}
void ProcessAllData()
{
// Here we process all records from HistoricalData table insert porcessing results into two other tables
}
void Rollback()
{
if (dbContextTransaction != null)
{
this.dbContextTransaction.Rollback();
}
}
void SaveData()
{
this.dbContextTransaction.Commit();
this.dbContextTransaction.Dispose();
}
}
Use as such:
HistoricalDataService service = new HistoricalDataService (dbcontext);
try
{
service.AddHistoricalData(HistoricalData instance);
service.ProcessAllData();
service.SaveData();
}
catch (Exception ex)
{
service.Rollback();
}
I would recommend refactoring the code so that the service has a single method (at a higher level of abstraction) and a single responsibility: handling the use case.
then, the client class would have
private readonly IHistoricalDataService _historicalDataService;
_historicalDataService.RearrangeSeatingArrangement(); //High level abstraction
the purpose of doing the above is to ensure your service class has all the operations occur within a single method, wrapped with either a transaction scope if using raw ADO.NET or context object if using EF. Dont have the client class call three methods when it could just call ONE. This is the purpose of the service class in the first place: Handle use cases and return response to client class ( perhaps controller in your case).
Now, when it comes to ensuring that some part of your code is aware of data that has been persisted, it brings up some additional questions: The commands that occur during ProcessAllData() above, why does it split the data exactly? Can that data that is split be split in memory ( in another domain class), added to the context, and saved in the SaveChanges() method? This would ensure you only make one call to the database ( which is the purpose of Entity Framework Unit Of Work. That is: accumulate changes in the context, adds, delete, udpates, then in one operation, talk with database).

EF DbContext Factory with Ninject C#

I am looking for some advice on the best way to re-structure an existing C# Console Application that I have written.
The application utilises Entity Framework for the Data coupled with the Repository pattern. I am also using Ninject for DI.
The issue I am facing is as follows:
I have a class, say ClassA, which has a Repository passed in through the constructor. The repository constructor takes in a DbContext. Ninject is currently handling all of this for me.
public class ClassA
{
private IRepository Repository;
public ClassA(IRepository repostitory)
{
Repository = repository;
}
public void Process()
{
var RV = Function1();
Function2(RV);
Function3(RV);
}
private IList<ClassB> Function1()
{
//Populate database using Repository and return list of objects
var items = //Call External Web Service to get list of Items
foreach(var item in items)
{
Repository.AddEntry(item);
}
return Repository.Items.ToList();
}
private void Function2(IList<Item> items)
{
//Long running process maybe 20/30 mins.
}
private void Function3(IList<Item> items)
{
//Remove objects in list from database via the Repository.
foreach(var item in items)
{
Repository.DeleteEntry(item);
}
}
}
public class Repository : IRepository
{
private DbContext DbContext;
public IQueryable<Item> Items
{
get { return DbContext.Items; }
}
public Repository(DbContext dbContext)
{
DbContext = dbContext;
}
void AddEntry(Item item)
{
DbContext.Items.Add(item);
DbContext.SaveChanges();
}
void DeleteEntry(Item item)
{
DbContext.Items.Remove(item);
DbContext.SaveChanges();
}
}
ClassA then has a process function that works through a series of 3 private functions.
Only functions 1 and 3 need access to the Repository, as 1 populates the database via the Repository and then returns an in memory collection. Function 2 uses this collection, after which function 3 deletes records from the database via the Repository.
Function 2 can take several minutes to complete and the behaviour I am noticing is that when function 3 calls the database I receive a "DbContext has been disposed" error. It has not been disposed in any of my code but it seems another process running on the same SQL server is causing this.
In an attempt to work around this I want to be able to dispose of the Repository after function 1 and then use a new one for function 3, so in essence wrap the code in function 1 & 3 inside a using statement. This is when my head starts to hurt when trying to figure out this scenario whilst utilising Ninject.
What should I be passing in to ClassA as part of the constructor to allow me to create on the fly Repostitories? Do I need some sort of Factory pattern or Unit of Work pattern?
Any help or thoughts gratefully received.
Thanks
pf79
You can inject your DbContext as a factory instead of an instance perse, take a look at this: https://github.com/vany0114/EF.DbContextFactory
http://elvanydev.com/EF-DbContextFactory/
There is an extension to Ninject to do that in a very easy way, just calling the method kernel.AddDbContextFactory<YourContext>(); also you need to change your repository by receiving a Func<YourContext>

Categories

Resources