I am having a tough time to understand why this code is failing
I have a test method
IUnitOfWork unitofwork = EFUnitOfWork.CreateInstance();
IRepository<InformationRequest> informationRequestRepository = unitofwork.CreateRepository<InformationRequest>();
IEnumerable<InformationRequest> requests = informationRequestRepository.ToList();
unitofwork.Dispose();
EFUnityOfWork.CreateInstance calls the EFUnitOfwork Constructor
public EFUnitOfWork()
{
_currentContext = new MyDataContext();
}
Here is the code for CreateRepository
public IRepository<T> CreateRepository<T>()
{
return new Repository<T>(_currentContext);
}
The test above doesnt work on a load test. When i try to run it it says
System.Data.EntityException: The underlying provider failed on Open. ---> System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
I am disposing the context and creating a new one everytime. I dont understand where i am going wrong
Your code EFUnitOfWork.CreateInstance() is a static method.
When 2 threads call this at the same time they could get back the same context. Then you could get the error that you see.
You could fix it by locking such that it is only called by one thread at a time. But time would introduce a performance bottleneck.
Related
I am fairly new to Entity Framework and everything has been moving smoothly, until I encountered this error. My code is attempting to save children of a parent table using SaveChanges() but I get this error:
A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext.
This message seems tied to async calls and having to use await - SaveChangesAsync(). However I am NOT calling the async version of the SaveChanges() method but still get a thread error message.
My code is fairly simple:
public void CreateRange(IList<Section> sections)
{
// Add new sections and save context.
_SqlRunnerContext.sectionsDbSet.AddRange(sections);
_SqlRunnerContext.SaveChanges(); // This line throws the error.
}
The error seems to occur when there are at least two entries in the list. Which makes me think it's the way that Entity Framework is handling the save internally.
The code that calls this method creates a new repository which in turn creates a new dao and SqlContext. Given this I wouldn't think it would be something outside of this code causing the issue. I have also tried a foreach loop and save each item individually with the same error.
If anyone could give me a suggestion or idea what to try, it would be much appreciated.
Thanks again,
Adam
Instead of deleting all records then re-inserting. I change the code to simply update if it exists and add if new. This has resolved the issue.
When implementing MVC project, I usually add Service Layer to perform the actual work. But actually sometimes 1 Web Request should be done with several AppService methods. Then the location of Unit-of-Work (UoW) may affect the coding handling.
No matter in C# EF/Java Spring, there's Transaction annotation in Service Layer methods, so the transaction is Per-Service based (i.e. UoW on Service layer). Let's take Java version as example here:
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
Public class UserAppService{
public UserDTO createUser() {
// Do sth to create a new user
userRepository.save(userBean);
// Convert userBean to userDTO
return userDTO;
}
public xxx DoSth() {
// Break the operation here
throw new Exception("Whatever");
// (never execute actually)
sthRepository.save(someBean);
}
}
Then in Controller:
Public class SomeController : Controller {
Public xxx DoSth(){
UserAppService Service = new UserAppService();
Service.CreateUser(); // DB committed
Service.DoSth(); //Exception thrown
}
}
With this structure, If there's any exception thrown on 2nd service method call, the 1st service method still commit the user to the DB. If I want "all-or-nothing" handling, this structure doesn't work unless I wrap those service method calls into another wrapper service call with single transaction. But it's sort of extra work.
Another version is using transaction on Controller action level instead (i.e. UoW on Controller Action). Let's take C# code as example:
Remarks: AppService in code version 2 here use the DbContext (sth like transaction) defined in controller, and doesn't do any commit inside.
Public class SomeController : Controller {
Public ActionResult DoSth(){
using (var DB = new DbContext()){
Var UserAppService = new UserAppService(DB);
var userEntity = userAppService.GetUser(userId);
UserAppService.DoSth(userEntity);
Var AnotherAppService = new AnotherAppService(DB);
AnotherAppService.DoSthElse(userEntity);
// Throw exception here
throw new Exception("Whatever");
DB.Save(); // commit
}
}
}
In this example, there will be no partial commit to the DB.
Is applying UoW on service-layer really better?
Is applying UoW on service-layer really better?
IMO No. And you've just figured out why. If the service methods are discreet and re-usable, they are also not suitable for being atomic transactions.
In .NET the controller should control the transaction lifecycle, and enlist service methods in the transaction.
Note that this also implies that the service methods should be local method calls, not remote or web service calls.
It is better because your following the main principle of Object Oriented Programming seperation of concerns.What if you made another controller and wanted to do more database processing using the same object? You dont want to instantiate the controller in which your doing something completely different.By the way check out the facade service pattern http://soapatterns.org/design_patterns/service_facade it may help you understand why its so sexy. .Hi the image above shows the pattern, basically you wrap your database access objects with transactional at the service layer so a customerService object can wrap 1,2...inf transactions and either all fail or succeed.
I have the following test code:
try
{
Product product = productService.GetProductById(1502);
product.ProductName = "TEST PRODUCT NAME";
throw new ArgumentException("");
//Do some other DB updates
//Call SaveChanges
productService.SaveChanges();
}
catch(Exception ex)
{
logService.InsertLog(LogTypeEnum.Error, "test", ex);
logService.SaveChanges();
}
The problem is that my services share a context per request (using StructureMaps HttpContextScoped). So when the failure occurs and I call logService.SaveChanges it saves the products new name. However I lose atomicity because the "other DB updates" will not be saved to the DB. What would be the correct way to implement this?
This is always going to be a problem with context per-request. In a large project I started out with context per-request too, but have gradually removed it due to problems like this.
I would suggest identifying the scenarios like this where you are likely to need to write to your DB without calling SaveChanges - if it's all limited to this log service then perhaps you should re-implement this without the dependence on the context? Alternatively you should be able to specify a custom way of creating the log service with its own context (i.e. not just having one injected by the constructor).
I'm not familiar with the Structuremap syntax so here's something from Autofac which would do the same...
builder.RegisterType<MyContext>().InstancePerRequest(); // As you have already
builder
.Register(c => new LogService(new MyContext())
.As<ILogService>().InstancePerRequest();
This would construct LogService using an explicitly created context rather than the per-request instance which would've been injected had I registered it normally.
Using autofac as my IoC framework.
I'd like to be able to set up my DbContext instance in my application's startup.
In my ASP.NET MVC 3 project, I register DbContext instance in Global.asax (PerLifetimeScope). But when I fire up my site on multiple browsers (or multiple tabs) at once, sometimes I get Object reference not set to an instance of an object. or New transaction is not allowed because there are other threads running in the session when I try to save changes back to database. Also I get
ExecuteReader requires an open and available Connection. The connection's current state: Broken. sometimes when I want to read data from database.
the errors seem to pop up randomly and I suspect it has something to do with my context's lifetime scope. here's my DbContext's overriden SaveChange method.
public class MyContext : DbContext
{
public override int SaveChanges()
{
var result = base.SaveChanges(); // Exception here
}
}
Here's how I register my context:
builder.Register(c => new MyContext("SomeConnectionString"))
.InstancePerLifetimeScope();
If I just have one open tab of my site in the browser everything works ok.
Also, It's worth mentioning I have CRUD operations with db every 5-10 seconds in my website by calling a controller method using Ajax.
StackTrace for New transaction is not allowed because there are other threads running in the session:
at System.Data.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.EntityClient.EntityConnection.BeginTransaction()
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs
StackTrace for Object reference not set to an instance of an object.:
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
at System.Data.Objects.ObjectStateManager.DetectChanges()
at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)
at System.Data.Entity.Internal.InternalContext.GetStateEntries()
at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
at System.Data.Entity.DbContext.GetValidationErrors()
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs at
Registration of MyContext looks ok. Is it possible that some other service that takes a MyContext is registered as a singleton and being shared across threads?
I had the same issue, sporadic errors related to the DbContext while using Autofac to resolve the DbContext.
{System.Data.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
etc.
{System.NullReferenceException: Object reference not set to an instance of an object.
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
etc.
I found a class resembling the following in my code. The dependency resolution was occurring within a static method inside of the singleton. The object being resolved had a dependency on the DbContext. I haven't had any additional issues after I found a way to restructure this class so that it was no longer a singleton.
Perhaps you have a similar situation? Another thing to try might be to make your DbContext InstancePerHttpRequest. That could help identify whether this is the issue.
public class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton()
{
}
public static void DoSomething<TSource>(TSource source) where TSource : ISource
{
var items = DependencyResolver.Current.Resolve<IEnumerable<IDbContextConsumer<TSource>>>();
foreach (var item in items)
{
item.Execute(source);
}
}
}
Albahari writes in "c# 4.0 in a nutshell":
>
Although DataContext/ObjectContext implement IDisposable, you can (in general)
get away without disposing instances. Disposing forces the context’s connection
to dispose—but this is usually unnecessary because L2S and EF close connections
automatically whenever you finish retrieving results from a query
<<
This feels wrong and FxCop also complains if you are not diposing something that is IDisposable.
I have the following repository code:
public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{ ...
public void Add(TEntity entity)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
dbContext.Set<TEntity>().Add(entity);
dbContext.SaveChanges();
}
}
...
public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
return dbContext.Set<TEntity>().Where(expression).ToList().AsEnumerable();
}
}
...
Note: I do not return IQueryable - lazy loading should not play a role.
Resolve DbContext is configured as PerResolveLifetimeManager.
Is this approach OK or do I need to reconsider this based on Albaharis description?
You should always call dispose if class exposes it. The statement claims that EF and L2S close connection whenever they finish operation - as I know the statement is correct but in the same time ADO.NET team also closes connection in Dispose method so perhaps there are situations when connection is not closed.
I'm working on EF 4.0 ObjectContext (yeah, I know...). I ended up looking at the code in DotPeek, and the dispose just nulls the reference to the connection and a few other things in the ObjectContext class.
When a connection is created (also found through DotPeek) it returns the existing instance. If the connection string is changed, it'll update the connection string for all instances.
That was my take on it at least. Need to look deeper but at first glance, it seems that you can get away with it.