ASP.NET MVC + EF Performance - c#

I have this code in my Controller:
public class MyController : Controller
{
private readonly IMyRepository myRepository;
public MyController() : this(new MyRepository())
{}
public MyController(IMyRepository myRepository)
{
this.myRepository = myRepository;
}
public ActionResult Index()
{
return View(myRepository.GetData());
}
}
MyRepository uses EF for data operations. Every time user loads this page instance of MyRepository is creating. That means EF context is creating and Fluent API code is executing (OnModelCreating method).
Are there any possibilities not to create EF context everytime when user loads the page?

MyRepository uses EF for data operations. Every time user loads this
page instance of MyRepository is creating. That means EF context is
creating and Fluent API code is executing (OnModelCreating method).
You're wrong. Put a breakpoint on your OnModelCreating method. This method will only get hit once, when your application loads. It will hit the breakpoint again if you rebuild the project, because this causes the binary dll to be reloaded into the app domain. However if you leave the application running and hit the controller action twice (without rebuilding in between), you will see that OnModelCreating does NOT get hit the second time. Like Serg Rogovtsev says, EF caches the model (meaning the schema) after it is created during OnModelCreating.
The only objection I have to Serg Rogovtsev's answer is that I would never create a singleton instance of the DbContext. Instead you should use one instance per HttpContext (a.k.a. per web request). If you use it as a singleton, and you have concurrency enabled, you would end up seeing DbConcurrencyExceptions creep up in your app. Use DI/IoC, and create/dispose the DbContext instance at the beginning/end of the request response cycle. That is the best practice. Don't worry about the overhead of creating a new MyDbContext() instance. After EF initializes (warms up) during the first construction, future constructions will be fairly cheap.

To answer your question: you can create a singleton of your repository or you can use DI container which will hold single instance for you.
But to the point: if you set breakpoint inside OnModelCreating you will find that it gets called only once per application instance. EntityFramework uses pretty effective model caching. So you don't have to worry about performance hit caused by creation of EF contexts.

Change your controller so you create an instance of your repository in a lazy way. You can use the Lazy < T > class for example.

In terms of performance I'd favour looking to persist data and not the context, the EF context is optimized to be created and then disposed to free up connections in the pool.
Some other EF performance methods at http://www.sql-server-performance.com/2012/entity-framework-performance-optimization/

Best practice is to dispose the EF context after you've retrieved/updated your data.

Related

ASP.NET MVC with EF and the Dispose Pattern

I'm writing an ASP.NET MVC application with EF. I have some questions regarding whether or not my approach is reasonable. Note: I simplified my basic structure for this question, in realitiy everything is coupled more loosely.
Let's assume a View that allows a user to change properties of a complex domain model. The data originates from the Database (via EF) and has to be written back again in the end.
From my understanding, each request results in a new controller instance being called. Therefore, I'm using the 'Dispose Pattern' described here as Option 2, which ensures a new DbContext for every request:
public class MyController : Controller
{
private MyContext repo = new MyContext();
protected override void Dispose(bool disposing)
{
this.repo.Dispose();
base.Dispose(disposing);
}
//more code...
}
Now there is a public ActionResult Edit(elementId) method on the controller that will fetch an element from the database and displays an editor for it. Once this request is finished, any reference to the Dbcontext is gone, but I still have access to the Entity-Object fetched from the DB as I store it in my session.
Later on the user presses a 'Save' button on the View. The request to the Save-method of my Controller once again creates a new instance of the Controller and therefore a new DbContext. The Entity-object stored in my session is retrieved and its properties are modified according to the user's input. To save the new state to the database, I have to attach it to the new context:
public void Save()
{
this.repo.MyTable.Attach(myEntity);
myEntity.Name = "New Name";
this.repo.SaveChanges();
}
This can only work once the old Controller with the original DbContext of myEntity has been disposed, otherwise 'Attach' would fail (unable to attach Entity to two contexts). I'm concerned whether or not I can rely on the old DbContext being disposed here.
Also: I know that using an IoC framework would be an alternative. How would that apply to my situation, what would be the benefits?
I think you've redacted too much of your code in an effort to "simplify" the question, and as a result, have actually obscured some important issues. However, based on the Save method you've posted, I can pretty well guess your issue. Your repo is most likely creating it's own context, which is a pretty big no-no.
To answer you overall question, the rationale for implementing IDisposable here is the same as anywhere else: any class that owns dependencies that implement IDisposable should also implement IDisposable. Here, your controller instantiates MyContext, so it should therefore dispose of MyContext when its done. Simple as that.
However, if you introduce dependency injection, and inject the context into the controller, then the controller no longer owns the context. Instead, the DI container will own it. Therefore, your controller should not dispose of the context, as it does not own it.
And, you should use dependency injection here. Your context should be injected into your repository and then your repository should be injected into your controller. This ensures that there's is only one context instance, and you won't have issues like you're experiencing now, where EF complains that the entity belongs to a different context.
Finally, I just want to parrot #SteveGreene in saying that there is absolutely no reason to store your entity in the session, and in fact there's many reasons you shouldn't, not the least of which being it will frustrate any efforts to move away from In Proc sessions to a more reliable session store. Once you're using something like StateServer, SQL Server, Redis, etc., anything you put in the session must be serializable, and entities are often quite difficult if not impossible to serialize, since they often have many relationships with other entities and often circular relationships with those entities.

Ado.net stored procedure inserts does not show on EF Code First queries instantly

In our system we have implemented custom ADO.NET data imports with stored procs to our database because the performance of EF Code First and Linq2Sql isn't really good enough for the amount of data we have to process.
The problem is that once the import job has completed it will still take several minutes to get the new data showing up on our views when it is queried with Code First DbContext and objects.
We are not using any custom caches or OutputCaches so the only thing caching the results must be EF itself. We are using Dependency injection on out MVC controllers to get service instance that provides the datamodel for the view. The scope is set to be per request so the service instances should be recreated once request hits that controller action, right?
Basically our services are deriving from the following base class that initializes the correct context.
public class ServiceBase<T> : IDisposable
where T : DbContext, new()
{
private T _context;
protected ServiceBase()
{
this._context = new T();
}
}
On our context we have set the Autodetectchanges to false
Configuration.AutoDetectChangesEnabled = false;
Also we are reloading our objectcontext entities after the imports job like this
var refreshableObjects = ObjectContext.ObjectStateManager
.GetObjectStateEntries(EntityState.Deleted | EntityState.Modified | EntityState.Unchanged)
.Where(o => o.EntityKey != null).Select(o => o.Entity);
ObjectContext.Refresh(RefreshMode.StoreWins, refreshableObjects);
But it is not working. I have tried to look up information on how to properly reload the DbContext but have not yet figured it out. Everywhere it says that disposing the context and recreating it should clear the cache but it doesn't seem to work.
Could someone help me? Much thanks!
If you know that changes happened outside of EF and want to refresh your ctxt for a specific entity, you can call ObjectContext.Refresh
datamodel.Refresh(RefreshMode.StoreWins, orders);
If this seems like it will be a common occurance, you should disable object caching in your queries:
SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.tblCities.MergeOption = MergeOption.NoTracking;
or for to turn off object level caching for specific Entity,
Context.Set<Compliances>().AsNoTracking();

Entity Framework DbContext and thread safety

I need to update a few tables in my DB in a single transaction and I read that using DbContext.SaveChanges should be the way to do so.
However I also read that the lifetime of the DbContext should be as short as possible because it grows over time as it loads more entities.
Also I read that in order to make it thread-safe, each action should have its own DbContext.
Should I have a DbContext for each table I want to change and call SaveChanges on each DbContext? Wouldn't the last SaveChanges call override the changes of the previous calls?
What is the best way to do it? (I need this for a website)
Entity Framework is not thread-safe. An MVC controller is instantiated per request. Thus if you use one DbContext per request, you're safe as long as you don't manually spawn threads in your controller actions (which you shouldn't do anyway).
Now if you have concurrency in your application, like a reservation system where multiple users are out to access the same scarce resources that can run out (like tickets), you'll have to implement logic around that yourself. No thread safety is going to help you there anyway.
That's why you're being asked for code in comments, because explaining thread safety in general is way too broad, and probably not applicable to your situation.
Simple way is, to have one DbContext per request, ASP.NET MVC does all thread safety, each controller instance in ASP.NET MVC is isolated for every request, you don't have to worry about race conditions. As long as you don't create threads and just simply do data transformation in action method using single DbContext, you will not have any problem.
Basically DbContext does nothing, it just queues SQL query to target database, it is the database which handles multi threading, race conditions. To protect your data, you should use transactions and add validations in your database to make sure they are saved correctly
public abstract class DbContextController : Controller{
public AppDbContext DB { get; private set;}
public DbContextController(){
DB = new AppDbContext();
}
protected override void OnDisposing(bool disposing){
DB.Dispose();
}
}
If you inherit any class from DbContextController and use DB throughout the life of controller, you will not have any problem.
public ActionResult ProcessProducts(){
foreach(var p in DB.Products){
p.Processed = true;
foreach(var order in p.Orders){
order.Processed = true;
}
}
DB.SaveChanges();
}
However, if you use any threads like in following example,
public ActionResult ProcessProducts(){
Parallel.ForEach(DB.Products, p=>{
p.Processed = true;
// this fails, as p.Orders query is fired
// from same DbContext in multiple threads
foreach(var order in p.Orders){
order.Processed = true;
}
});
DB.SaveChanges();
}

Entity Framework + Autofac: How to properly reload mappings / configurations?

BACKGROUND:
Our core framework loads all entity framework mappings from itself, the main application and any modules we have installed by using an interface (below):
public interface IEntityTypeConfiguration : IDependency
{
}
and we have a DbContext in our core framework like this, which loads all the mappings:
public class DefaultDbContext : DbContextBase
{
private readonly Lazy<IEnumerable<IEntityTypeConfiguration>> configurations;
public DefaultDbContext(Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base()
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
public DefaultDbContext(string connectionString, Lazy<IEnumerable<IEntityTypeConfiguration>> configurations)
: base(connectionString)
{
this.configurations = configurations;
Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (dynamic typeConfiguration in configurations.Value)
{
modelBuilder.Configurations.Add(typeConfiguration);
}
Database.SetInitializer(new CreateTablesIfNotExist<DefaultDbContext>());
}
}
So this way we have a single DbContext for everything.
PROBLEM:
We've run into an issue whereby when we dynamically add new modules (which have their own mappings), then EF does not load those mappings ever, even when we are sure that a new instance of DefaultDbContext has been created. So, it must be that EF is cacheing the mappings somewhere. Is there some way to clear the cache?
FINAL NOTE:
As you may have guessed, we are using an IoC, namely Autofac. If you need any further info, just ask.
Any ideas, anyone?
The model is cached for performance reasons.
The following excerpt explains what is going on
Model Caching
There is some cost involved in discovering the model, processing Data Annotations and applying fluent API configuration. To avoid incurring this cost every time a derived DbContext is instantiated the model is cached during the first initialization. The cached model is then re-used each time the same derived context is constructed in the same AppDomain.
This text also mentions a property called CacheForContextType but this didn't make it into the final release of EF5.
This second link provides a glimmer of hope but again is dated before the final release of EF5
We removed CacheForContextType in CTP5, we originally intended it to be used when folks wanted to use the same context in the same AppDomain with different models. The issue is that it would create the model on every initialization and didn't allow any way to cache a series of models and choose which one to use during each initialization. Model creation is expensive so we wanted to promote a better pattern.
The pattern we recommend is to externally create a ModelBuilder -> DbDatabaseMapping -> DbModel for each model you want to use. The DbModel should be cached and used to create context instances. The ModelBuilder -> DbModel workflow is a little messy and the class names aren't great, they will be tidied up for RTM.
Personally I think you're going to have to find a way of knowing all of your models up front ...
Solved! We found this constructor on the DbContext class:
public DbContext(string nameOrConnectionString, DbCompiledModel model);
I can't share all of the code here, but basically we're creating a new DbCompiledModel and passing that in whenever necessary.

session state variables and singleton class

I have a situation where I need to retrieve data from a query which executes for almost half a minute and bring it to a web page. (There is no way to reduce this time because the maximum amount of optimization has been performed on it)
I use a four layer architecture along with Entity Framework ( EF, Data Access Layer, Biz Logic Layer, UI) for my application.
I'm trying to use the singleton method when an instance to the DAL is created (The DAL in turn retrieves data from the database) so that I will be able to re-use this instance and hence additional instances wont be created within the same session.
How do I go about setting the session state and checking the availability of the instance in the State Server?
public static Singleton getInstance() {
if (**instance == null**)
instance = new Singleton();
return instance;
}
What should reside within the if block? What condition should I check for in the if block? I'm really unsure as to what I must do.
PS: This session must have a timeout of 5 mins. I hear this can be specified in the Web.config file. is it true?
To be honest you should rather use Entity Framework context and create it every time you need access to database, i.e. in each method. It is optimized to be used that way. Connection pooling will make sure there is not penalty in recreating EF context each time. This is the best practice.
But your DAL might be more than just simple DB access. If you want to have it as a singleton separate for each session you must create the instance on the first request, store it into the Session and check if it's there before using. With thread safety the code could look like that:
class DALClass
{
private static object instanceLock = new object();
public static DALClass Instance
{
get
{
if (Session["DALInstance"] == null)
{
lock (instanceLock)
{
if (Session["DALInstance"] == null)
{
Session["DALInstance"] = new DALClass();
}
}
}
return (DALClass)Session["DALInstance"];
}
}
}
It sounds to me like you have a well defined architecture which would suit dependency injection. Using DI you could just get your IOC container to return you a singleton object or a transient one. However, be very careful using singletons in a web environment as they often cause more trouble than they are worth.
If the query you are running contains user specific data then I would probably place the results of that query into session within the code which composes the UI part of your application if you are using a pattern like MVC that would be in the controller or MVP in the presenter.
If these patterns aren’t in use then you could consider placing the information into session inside the business layer but only if you wrap up the session and inject in that dependency into your business object, e.g. something like “IUserSession”. The business project should not contain a reference to “system.Web” or anything like that.

Categories