Is this a bad way of using DbContext for EF CodeFirst? - c#

I have one base controller class which has following DbContext. Instead of using "using" statement for each database work, can I rely on this. So far app runs as expected. I am not sure if Dispose part is really needed.
private static Context _database;
public static Context Db
{
get
{
if (_database == null)
{
_database = new Context();
}
return _database;
}
}
protected override void Dispose(bool disposing)
{
if (_database == null)
{
_database.Dispose();
}
base.Dispose(disposing);
}

No. not sure what class is being disposed of here but if it ever got disposed it would crash every time after that. you have to set _database = null after calling dispose or you would use it in a disposed state. if you want to do any type of multi threading this won't work. if more than 1 user is using this at same time it will crash. you won't be able to unit test the use of database with static either. It will cache all data you get causing stale data after a time too unless you are only user.

Having a automatic disposal of requests is very convenient don't make it a manual task.
Just don't use static in anyway, always using usingstatement for every request.

Related

How to dispose the ContextDB class automatically after any query done using it

ASP.NET MVC 5 Project.
I know that the best practice of using EF context object as the following
using(var context = new ContextDB())
{
}
But I am working with a large existing project which not used this practice.
the project using the following pattern
public abstract class BaseService
{
private static ContextDB _data { get; set; }
public static ContextDB Data
{
get
{
if (_data== null)
_data= new ContextDB();
return _data;
}
}
}
Actually, because of this pattern, I am receiving this exception (sometimes, not always)
So to solve this I have to change all the code which is using the shared Data
property and replace it with the new instance of ContextDB as I mentioned in the beginning of the question.
The problem that this is a very large modification, and I will not be allowed to do that modification.
The Question, can I solve this problem without changing a ton of code, In another word, can I solve the problems with modifications done only inside the BaseService class, for example, Is there any event which I could handle to know if any query is executed and then dispose of the ContextDB
here is the pseudo-code of the idea in my mind
public abstract class BaseService
{
public static ContextDB Data
{
get
{
ContextDB _data= new ContextDB();
_data.SqlQueryExecuted += () => { this._data.dispose(); }
return _data;
}
}
}
NOTE: the SaveChanged event is not suitable, because not all of the query are updating or inserting.
I may use following solution.
In Global.asax
Begin Request : Create Instance of your dbContext. Store it in HttpContext.Current.Items.
End Request : Grab the context and close / dispose connection.
Another better solution is to use DI. Dependency Injection and limit the scope of your instance. There are many way Like Singleton, PerRequest etc.

The context cannot be used while the model is being created exception [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I've got the following error using Entity Framework 6.0.0.0.
The context cannot be used while the model is being created.
This exception may be thrown if the context is used inside the
OnModelCreating method or
if the same context instance
is accessed by multiple threads concurrently.
Note that instance members of DbContext and
related classes are not guaranteed to be thread safe.
It is fired inside an async method
,upd:
public async Task<IList<Model>> GetEntities(filter f)
{
using (var db = new MyDbContext())
{
var query = db.MyDbSet.AsQueryable();
if (f != null && f.field.Any())
//Exception throwed here
query = query.Where(a => f.field.Contains(a.field));
return await query.ToListAsync();
}
}
But any await calls or other multithreading operation is not performed when i try to find my entities by Where clause.
Are any suggestions related to that issue ? I found a lot of answers but didn't found their helpful for me.
If your management studio has been able to connect successfully to the database
then do this. Run your management studio and before you connect to the database
copy out the full "Server name" and use this to replace your "host" and confirm that the actual name of the particular database you are trying to connect to is called "database" and if not replace "database" with that name. Finally if you management studio requires a user name and password to connect to the database then you have to include those as well. From the error you are getting the problem is connecting to your database. Let me know how it goes.
You want to implement a proper method of connecting to your database that disposes the connection, or uses a term called "dependency injection" - creating an interface and instance of the DataContext that is able to be accessed at any time by any function in the controller. Here are examples of the 2 methods:
Dispose Architecture
This architecture requires that you declare your DataContext before any other function, and add a Dispose function in the Controller at the end.
Some specific oddities I found and fixed in the code:
You should be returning a ViewModel or a data model that represents a database table or view you are querying, in this case MyDbSet, not Model.
You should be using the db instance declared generically for the class.
You should define what filter is. An array? A model? A string? I'm going to assume it's a list of strings like this: string[] filter = { "Fruits", "Meats", "Dairy" };
The Where clause might not be correct on your query, but again, I don't know what your filter looks like. There's other examples here: https://learn.microsoft.com/en-us/dotnet/api/system.linq.queryable.where?view=netframework-4.8
MyDbContext db = new MyDbContext();
public async Task<IList<MyDbSet>> GetEntities(filter f)
{
using (db)
{
var query = null;
if (f != null && f.field.Any())
{
query = db.MyDbSet.AsQueryable().Where((a, index) => a == f);
}
return await query.ToListAsync();
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
Dependency Injection
I describe this process thoroughly in another SO post, here:
How to inject my dbContext with Unity
The main difference is you would do something like this in your controller's GetEntities function to get the data:
query = repository.GetMyDbSet.Where((a, index) => a == f);
Mostly the same as above, but you don't need the using(db) { ... } statement, anymore.
You would have an interface:
public interface IDataRepository
{
void SaveChanges();
IEnumerable<MyDbSet> GetMyDbSet();
}
and a repository class function to return the data to you:
public IEnumerable<MyDbSet> GetMyDbSet()
{
return context.MyDbSet;
}
And context is defined in a Repository class:
public class DataRepository : IDataRepository
{
private bool disposing;
private readonly MyDbContext context;
public virtual void Dispose()
{
if (disposing)
{
return;
}
disposing = true;
if (context != null)
{
context.Dispose();
}
}
public void SaveChanges()
{
context.SaveChanges();
}
public DataRepository()
{
context = new MyDbContext();
context.Configuration.ProxyCreationEnabled = false;
}
public IEnumerable<MyDbSet> GetMyDbSet()
{
return context.MyDbSet;
}
}
Hopefully this helps you or someone.

Log EF query time to database

I want to log EF query (or transaction) times back to the database so that I can monitor performance in a live system. Note I know that more than one query can happen within my UOW. That is fine, I just want to be able to tell what areas of the system are slowing down etc.
What is the best way for me to do this? My initial thought was to do this in UnitOfWork.Dispose() so that every query would automatically be logged once completed. But this smells a bit to me because I'd have to call Save() to persist the information, but what if the caller didn't want to save?
Is there another, better way I can automatically log the query time to the database?
protected virtual void Dispose(bool disposing)
{
if (this.logQueryToDatabase)
{
var timeTaken = DateTime.UtcNow - this.start;
LogPerformance(this.callingFnName, timeTaken.TotalMilliseconds);
}
this.ctx.Dispose();
}
If you know which actions to measure you can create a simple class to handle this. All you need is to wrap around the action.
The profiler class.
public class Profiler:IDisposable
{
private readonly string _msg;
private Stopwatch _sw;
public Profiler(string msg)
{
_msg = msg;
_sw = Stopwatch.StartNew();
}
public void Dispose()
{
_sw.Stop();
LogPerformance(_msg, _sw.ElapsedMilliseconds);
}
}
The usage:
using (new Profiler("Saving products"))
{
db.SaveChanges();
}

Web Forms - Entity Framework Context Disposal

I have a .NET 4 Web Application (Web Forms) that uses Entity Framework to manage data with a MySQL Database. For every Page, I create the context for this Model in the Page_Load.
string connString = ConfigurationManager.ConnectionStrings["dbconnection"].ToString();
MyModel = new MyEntities(connString);
Now, in subsequent actions on the Page I can use MyModel to retrieve and update data. This is clean and simple to me, but I always assumed .NET discarded the previous Page's MyModel when a new page request was made. I realize this may not be the case? and Memory may be being used inefficiently.
I have seen a good case being made for incorporating the using (MyEntities MyModel = new MyEntities (ConfigurationManager.ConnectionStrings["dbconnection"].ToString())) that handles disposal, but this does not seem clean if I have 6+ actions on a Page each needing to recreate the context when called (Not that my current method does any better).
Is there a clean way to create a context once on initial Page Load and dispose of it when a new page is called, non-postback is called, or the user's session ends?
You can override virtual Dispose method of System.Web.UI.Control and dispose of your context there:
public override void Dispose()
{
if (MyModel != null)
MyModel.Dispose();
base.Dispose();
}
Further, you can make MyModel into a property with the context created on demand:
private MyEntities fMyModel = null;
protected MyEntities MyModel
{
get
{
if (fMyModel == null)
{
string connString = ConfigurationManager.ConnectionStrings["dbconnection"].ToString();
fMyModel = new MyEntities(connString);
}
return fMyModel;
}
}
Then, in Dispose work with the field:
public override void Dispose()
{
if (fMyModel != null)
fMyModel.Dispose();
base.Dispose();
}
Furthermore, you can create a base Page class with the above property and Dispose override and inherit your pages from it - then you do not need to repeat this code in all your pages.
The easiest thing to do would be to add a call to Dispose() on your data context in the Unload event on the page.
protected void Page_Unload(object sender, EventArgs e)
{
MyModel.Dispose();
}
A better way that I think should be used as default for web applications (doesn't matter if it is WebForms or MVC is to create one data context per request and dispose it when the request ends. To do that easily you can use an IoC container framework such as Ninject.

Good way to manage DataContext in ASP.NET? SqlException: Server failed to resume the transaction

We create one Linq2Sql DataContext for every request using the following class:
public static class DataContextManager
{
private const string HTTPCONTEXT_KEY = "DataContextManagerKey";
private static CompanyDataContext _staticContext; //when there's no HttpContext (in test/debug situations).
public static CompanyDataContext Context
{
get
{
if (_Context == null)
{
_Context = NewContext();
}
return _Context;
}
}
private static CompanyDataContext _Context
{
get
{
return (CompanyDataContext)(HttpContext.Current != null ? HttpContext.Current.Items[HTTPCONTEXT_KEY] : _staticContext);
}
set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[HTTPCONTEXT_KEY] = value;
}
else
{
DataContextManager._staticContext = value;
}
}
}
public static void Dispose()
{
CompanyDataContext context = _Context;
if (context != null)
{
if (Config.Instance.TestMode) context.Log.WriteLine("--- DISPOSING DATACONTEXT ---");
context.Dispose();
_Context = null;
}
}
public static CompanyDataContext NewContext()
{
CompanyDataContext db = new CompanyDataContext();
db.CommandTimeout = Config.SQL_COMMAND_TIMEOUT;
if (Config.Instance.TestMode)
{
db.Log = new ConsoleTextWriter();
db.Log.WriteLine("--- CREATING NEW DATACONTEXT ---");
}
return db;
}
}
And in Global.asax:
protected void Application_EndRequest(Object sender, EventArgs e)
{
DataContextManager.Dispose();
}
The reason why I'm asking is that we're suddenly getting random "SqlException: Server failed to resume the transaction" exceptions once or twice every day with code that used to work perfectly. After the exception we get a lot of other exceptions until we restart the web application. Anyone seen this behaviour before?
We're running ASP .Net 2.0 with SQL server 2005 on IIS 6.
UPDATE:
Just so no one else does the same horrible mistake as we did:
It turned out that some worker threads also used the DataContext but with no HttpContext they of course got the _staticContext (a feature in DataContextManager only to be used when testing). We rewrote the code in the worker threads to make sure one DataContext per thread and disposing it when done. And so far everything has worked for 2 weeks :)
This is a bad pattern. First you should never have a static data context it implements IDisposable so one thread could try to use the context while another is disposing of it plus many other potential problems. One data context per http request is no good either, data contexts are designed to be used for a single transaction then disposed of. You get problems if you retrieve update/insert/delete and retrieve using the same context, the second retrieve does not reflect the changes of the update/insert/delete. Remove the static context and just have the Context property return a new context every time. You could still dispose of the all at the end of a request by sticking them all in a List property and iterating through it.

Categories

Resources