If you query the DbSet of a DbContext, the query is valid until the DbContext is disposed. The following will lead to an exception:
IQueryable<Video> allVideos = null;
using (var context = new MyDbContext())
{
allVideos = context.Videos;
}
var firstVideo = allVideos.first();
Apparently the used DbSet is stored somewhere in the returned object that implements the IQueryable.
However, MSDN advises (Link)
When working with Web applications, use a context instance per request.
Of course I could use ToList() and return the result as a list of objects, but this is rather undesirable because I don't know the reason for the query.
Example: Suppose my database has a collection countries, which have cities, which have streets, which have houses, which have families which have persons which have names.
If someone asks for the IQueryable, then it could be that he wants to search for the name of the oldest person living on Downing Street nr 10 in London in the United Kingdom.
If I returned the sequence with a ToList(), all cities, streets, houses, persons, etc would be returned, which would be quite a waste if he only needed the name of this one person. That's the nice thing about deferred execution of Linq.
So I can't return ToList(), I have to return the IQueryable.
So what I'd like to do, is open a new DbContext, and somehow tell the query that it should use the new DbContext:
IQueryable<Video> allVideos = null;
using (var context = new MyDbContext())
{
allVideos = context.Videos;
}
// do something else
using (var context = new MyDbContext())
{
// here some code to attach the query to the new context
var firstVideo = allVideos.first();
}
How to do this?
The local guru happened to pass by. He explained to me that the error in my design was that I already use a DbContext while I am only composing the query. My interface should be such that I only need the DbContext when actually materializing the requested objects.
The question was a simplified version of the following:
I have a DbContext, with several public DbSet properties. These properties mirror the actual database. I want to hide the actual database implementation in my Abstract Database Layer in order to protect my data. I don't want anyone to give access change the contents of the database without having checked whether these contents are correct.
This is easy: just don't expose your actual DbContext to the outside world, but expose a facade that hides the actually used DbContext. This facade communicates with the actual DbContext.
With most functions that return an IQueryable I need the DbContext to access the DbSets. That's why I thought to create a context, construct the query and Dispose the context. But because of the deferred execution the context is still needed.
The solution
The solution is not to create your own context, but let the caller construct the DbContext. This constructed DbContext will be one of the parameters of the function. In that case the external user can call several functions of my facade to concatenate the query, even mix with his own Linq queries on the DbContext without creating and disposing the context. So like others suggested:
Callers creates the dbContext
Caller calls several of my functions that return a query, pass the dbContext as parameter
Caller executes the query by using ToList() / ToArray() / First() / Count() etc.
Caller disposes the context
To make it even nicer, the dbContext parameter is used in an extension method:
public static IQueryable<Video> GetObsoleteVideos(this MyDbContext dbContext)
{
// perform several difficult Linq statements on context
// that will return all obsolete videos
return ...
}
public static IQueryable<Video> GetThrillerVideos(this MyDbContext dbContext)
{
return dbContext.Videos.Where(video => video.Genre == VideoGenre.Thriller);
}
usage:
using (var myContext = new MyDbContext())
{
var difficultQuery = myContext.GetObsoleteVideos()
.Where(video => video.Name == ...)
.GetThrillerVideos()
.Take(10);
// Note: the query still deferred, execute it now, before Disposing myContext
var result = difficultQuery.ToList();
}
This way (and especially if I create an interface) I am able to prohibit access to my DbSets. I am even free to internally reorganize my Db and DbContext without external users noticing anything.
There are methods in the object context to do this:
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
objectContext.Detach(entity);
objectContext.Attach(entity);
However, as it says in the quote from MSDN, you should use one instance of the EF context per request. This refers to the HttpRequest not to a single query. When you do operations in one request, you should not put using blocks around your EF context and you should extend its lifetime. For new requests, it is advisable not to keep states across requests but rather follow the protocol
Query the item again and reload (another request might have modified it in the meantime)
Make the modifications
Save
Related
Update: #StriplingWarrior's answer has set me on the right track, but I have new questions detailed in this post.
In my organization there are three different groups using three different databases. The schema of the databases are the same -- same table structure, relational logic, etc -- and the three groups need me to report on their data in my application in the same way.
I understand that in my application I need to create a separate data context for each database, and in my repositories I need to explicitly declare the data context(s) used by that repository. I'm fine with all of that.
But if all three repos need to run the same given method, just against different data contexts, do I really need to write the same method three times? Is there no way that I can put my method in a class library, say, or some other fourth file, and then run the method against the context I need to use as and when?
For example, my repo looks like this:
public interface IMyRepo
{
List<string> GetMyData();
}
public class MyRepo : IMyRepo
{
private readonly ContextA _context;
public MyRepo(ContextA context) {
_context = context;
}
public List<string> GetMyData()
{
//code to get my data and return it
}
}
Now remember that because of the way my org's database is setup, I need to write this repo three times, once for each group. All that changes is the context.
I'd like to take the actual code for method GetMyData() and move it to a fourth file, then just link my repo to that file and call the method through an object reference, passing the context as a parameter, say. So I could call GetMyData() from my repo above like this:
//method call in my context above
public List<string> GetMyData()
{
//call actual GetMyData() method in my linked file
return linkedFile.GetMyData(_context);
}
Is something even remotely like I describe possible?
EDIT: I was asked by #RStevoUK to provide a code example for the linked file I describe, so I'll try to explain here.
So in my context I have the method GetMyData(), which runs certain code and returns a list object. In the .NET Framework days, I could put the actual code for GetMyData() into a separate class file, and then pass in the ConnectionString object that the method would use to connect to the correct database and retrieve its data.
CLASS:
public class ExternalClassFile
{
public List<string> GetMyData(string connectionString)
{
using (SqlConnection connectionString)
{
//code to get my data and return it
}
}
}
Then, to run this method against a given database, all I would need to do is call an instance of the class, and invoke the method with the correct connection string:
ExternalClassFile ecf = new ExternalClassFile();
public List<string> CallSharedMethod()
{
string connection = \\connecting string code;
return ecf.GetMyData(connection);
}
I don't think I can do that with MVC; what I understand of it leads me to believe I can't. Also, I don't think Generics are what I want, since GetMyData() would contain an actual linq query
var data = (from d in _context.DatabaseTable_Model
select d).ToList();
for example. That "_context" variable references my datacontext, and that's all that changes.
I've tried to setup a "_context" variable using a "var" declaration instead of a specific context name, but MVC doesn't like that. Is there something else I can try that would make the above linq example reusable among multiple contexts?
I hope this makes more sense.
What I'm hearing is that the only difference between your three repositories would be the specific type of DbContext that gets injected into them. And the only reason you're stuck being tightly coupled to a given type is that you have code accessing a property on that type, like _context.DatabaseTable_Model.
You can typically rewrite your data access code to rely on DbSet<> instead of a specific DbContext type. And you can get a generic DbSet<> off of any DbContext by calling its DbContext.Set<>() method.
var baseQuery = var data = _context.Set<DatabaseTable_Model>();
var data = (from d in baseQuery
select d).ToList();
Then you can make your repo take any type of DbContext:
private readonly DbContext _context;
public MyRepo(DbContext context) {
_context = context;
}
However, it's worth challenging the assumption that you need three separate data context types in the first place. If the schemas of the databases are literally the same, then the only difference between these classes should be their name, right? And the only reason the name matters is because DbContext's default constructor uses naming conventions to decide how to find the connection string to use.
DbContext has other constructors, though, so if you make your context class use one of those other constructors it should be perfectly possible to construct separate instances of the same class pointing at different databases by passing in the name of the connection string (or the actual connection string, or the connection itself) that you want it to use.
We currently use Entity Framework to access our DB. We had one large class, thousands of rows long, full of methods that queried database.
void saveFirstThing() {
using (var dbContext = new DatabaseContext()) {
...
}
}
AnotherThing returnAnotherThing() {
using (var dbContext = new DatabaseContext()) {
...
}
}
...
But if we wanted to change database provider (or test our application by using fake values), it would be pretty annoying to do. So I created:
interface IRepository<T>, which provides actions with T - Get(int id), Add(T entity), GetAll(), ...
Implementation of the interface, that implemented the methods by calling EF and returning IQueryable.
public class AnotherThingRepository : IRepository<AnotherThing> {
...
public IQueryable GetAll() {
...
}
...
}
public class Something {
AnotherThing returnAnotherThing() {
return anotherThingRepository.GetAll().Where(...).Single();
}
}
However, I have a problem. We have methods that require joins over multiple tables. So I cannot use using(dbContext) inside implementation of IRepository, since it would drop dbContext before we finish querying the result (of type IQueryable). I cannot return IEnumerable or List, since it won't load all joined fields (and there might be lot of them). If I wanted to do some messy reflection, it would be slow and full of circular references that I would need to solve.
What is the best solution? The only thing that works now is keeping dbContext forever, and share it for all queries in given repository implementation. However it stops working when I need to update something from DB, since dbContext caches everything and dbContext shouldn't be used in a way how I'm using it right now regardless.
The only thing that works now is keeping dbContext forever, and share it for all queries in given repository implementation.
No. The DbContext should be scoped to the Unit-of-Work, which might span involve multiple repository instances.
A simple implementation would inject the DbContext in the constructor of each of your repository types. eg
using (var db = new MyDatabase())
{
var things = new ThingRepository(db);
var anotherThings = new AnotherThingRepository(db);
. . .
db.SaveChanges();
}
Im new to C# and Entity Framework and I have a question about fields and initialization of a database class.
I have received some code in a program from my teacher that has a connection to a MySQL database through Entity Framework.
So far we have seen examples where inside methods for adding stuff to the database you first create an instance of it. An example of what we have seen so far:
using (var db = new p4_databaseEntities())
{
cp_car carEntity = new cp_car();
carEntity.make = car.make;
carEntity.model = car.model;
carEntity.year = car.year;
db.cp_car.Add(carEntity); //
db.SaveChanges();
MessageBox.Show("A Car has been added");
}
this.Close();
cp_car is a table in the database and a class in the program.
db is the current instance of the database.
Now, in the code I have received, this is not done this way. Its done in a different matter. Btw the program is a windows forms.
In the first form window, inside the constructor, he has created a new instance of the database and he calls upon a method called init
from the another class called LinqQueries. The code for that:
public Form1()
{
InitializeComponent();
p4_databaseEntities db = new p4_databaseEntities();
LinqQueries.Init(db);
this.CenterToScreen();
}
How the LinqQueries class looks:
private static p4_databaseEntities _db;
public static void Init(p4_databaseEntities db)
{
_db = db;
}
As I understand he created a new instance of the database in the constructor, where he also called on the init method. This method then defined the db object as _db. Now every single method he makes for adding or removing data from the database he is using _db and not db.
My question is does this mean that the init method assigns the static field of type p4_databaseEntities (name of database class) as an object? Is the value of the _db then an object? Is it a reference to an object? And also i noticed he uses the same field over and over again when making changes to the database which led me to believe it may be an active object that doesn’t die through out the programs lifespan?
If anyone could clarify this It would be greatly appreciated. Excuse any errors or wrong statements I have made please correct me if im wrong in any way. Im new to C# and Entity Framework.
Thanks beforehand
You are a bit inaccurate in your descriptions. This attributes to your confusion.
A DbContext is not a database, it represents the connection to the database. If you construct a DbContext object, you get access to the tables in the database via the Entities described in the DbSet.
Although it seems that a DbSet represents a table in the database, it does not. For instance an entity that you access via a DbSet can have an ICollection as member, which contains items that are not part of the table, but are items in a different table. Accessing the items in this ICollection causes an SQL Join to be performed, without you having to type the join
Hence a DbSet object in the DbConnection does not represent database table, it represents the access to the properties that can be accessed using the DbSet object, inclusive the properties of all objects in the database that are in tables that have a relation with the DbSet object.
Your first code with the using statement is the normal way entity framework should be used.
To hide the design of the database, quite often a separate class is introduced that is the only one that should use the DbContext. All users of the database should communicate using the seperate class.
This allows changing the internals of the database without having to change the code that uses the database.
This is what probably was meant as the purpose of the LinqQueries class. Instead of calling functions of the DbContext directly, users should call the (probably static) functions of LinqQueries. This way the internal structure of the database can change without having to change the callers of the LinqQueries functions.
What in fact is happening is that LinqQueries is meant to communicate with only one DbContext. LinqQueries does not decide which DbContext is used. Proper functioning depends heavily on exactly one user of LinqQueries who should create a DbContext and Init LinqQueries. This one user should also know when no one needs the LinqQueries anymore, because he has to Dispose() the DbContext.
This design if fairly error prone. Supposing the designer makes very grood products, his products will be used by a lot of users (meaning software, not operators). How do you assert that exactly one user will call the Init function?
If you really want that all users use the same Dbcontext, why not let the constructor of LinqQueries create this DbContext. In fact the design is similar to the singleton design pattern, so why not create LinqQueries as a singleton.
The limitation that all users of LinqQuery should use the same one and only DbContext limits the use of the LinqQuery class unnecessarily.
If users of the LinqQuery class could pass a DbContext to the constructor, then users could decide which database should be used by this particular LinqQueries object. This is quite handy when creating unit tests: instead of using the original database, the testable code could be used with a database with specific test values.
All in all the goal of the designer is unclear. IMHO it is a bad design and you are right that it is not clear what happens.
class LinqQueries
{
// default constructor: use the default DbContext
public LinqQueries()
{
this.DbContext = new p4_databaseEntities();
}
// special constructor: user provided dbContext
public LinqQueries(p4_databaseEntities dbContext)
{
this.dbContext = dbContext;
}
private readonly p4_databaseEntities dbContext;
public IEnumerable<...> GetMyElements(...)
{
return this.dbContext....;
}
}
This way, every creator of the LinqQueries would exactly know what to do either use the default p4_databaseEntities or create your own Dbcontext and dispose it when not needed anymore
using (var mydbContext = new p4_databaseEntities())
{
LinqQueries linqQueries = new LinqQueries(myDbContext);
// note that this constructor is very lightWeight!
var result = linqQueries.MyQeury(...);
}
This method is really safe. Any errors made by me, does not influence the code of any other user of the LinqQuery class.
I'm using EF 6 to work with a somewhat shoddily constructed database. I'm using a code-first model.
A lot of the logical relations there aren't implemented correctly using keys, but use various other strategies (Such as character-separated ids or strings, for example) that were previously manipulated using complex SQL queries.
(Changing the schema is not an option)
I really want to capture those relations as properties. It's possible to do this by using explicit queries instead of defining actual relations using the fluent/attribute syntax.
I'm planning to do this by having IQueryable<T> properties that perform a query. For example:
partial class Product {
public IQueryable<tblCategory> SubCategories {
get {
//SubCategoriesID is a string like "1234, 12351, 12" containing a list of IDs.
var ids = SubCategoriesID.Split(',').Select(x => int.Parse(x.Trim()));
return from category in this.GetContext().tblCategories
where ids.Contains(category.CategoryID)
select category;
}
}
}
(The GetContext() method is an extension method that somehow acquires an appropriate DbContext)
However, is there a better way to do this that I'm not familiar with?
Furthermore, if I do do this, what's the best way of getting the DbContext for the operation? It could be:
Just create a new one. I'm a bit leery of doing this, since I don't know much about how they work.
Use some tricks to get the context that was used to create this specific instance.
Do something else?
First, I would recommend not returning an IQueryable, as that retains a relationship to the original DbContext. Instead, I'd ToList the results of the query and return that as an IEnumerable<tblCategory>
Try not to keep DbContext instances hanging around; there's a lot of state management baked into them, and since they are not thread-safe you don't want to have multiple threads hitting the same instance. The pattern I personally tend to follow on data access methods is to use a new DbContext in a using block:
using (var ctx = new YourDbContextTypeHere()) {
return (from category in ctx.tblCategories
where ids.Contains(category.CategoryID)
select category).ToList();
}
Beware that .Contains() on a list of ids is very slow in EF, i.e. try to avoid it. I'd use subqueries, such as
var subcategories = context.SubCategories.Where(...);
var categories = context.Categories.Where(x => subCategories.Select(x => x.Id).Contains(category.CategoryId);
In this setup, you can avoid loading all the ids onto the server, and the query will be fast.
I have a number of static methods that perform simple operations like insert or delete a record. All these methods follow this template of using:
public static UserDataModel FromEmail(string email)
{
using (var db = new MyWebAppDataContext())
{
db.ObjectTrackingEnabled = false;
return (from u in db.UserDataModels
where u.Email == email
select u).Single();
}
}
I also have a few methods that need to perform multiple operations that use a DataContext:
public static UserPreferencesDataModel Preferences(string email)
{
return UserDataModel.Preferences(UserDataModel.FromEmail(email));
}
private static UserPreferencesViewModel Preferences(UserDataModel user)
{
using(var db = new MyWebAppDataContext())
{
var preferences = (from u in db.UserDataModels
where u == user
select u.Preferences).Single();
return new UserPreferencesViewModel(preferences);
}
}
I like that I can divide simple operations into faux-stored procedures in my data models with static methods like FromEmail(), but I'm concerned about the cost of having Preferences() invoking two connections (right?) via the two using DataContext statements.
Do I need to be? Is what I'm doing less efficient than using a single using(var db = new MyWebAppDataContext()) statement?
If you examine those "two" operations, you might see that they could be performed in 1 database roundtrip. Minimizing database roundtrips is a major performance objective (second to minimizing database io).
If you have multiple datacontexts, they view the same record differently. Normally, ObjectTracking requires that the same instance is always used to represent a single record. If you have 2 DataContexts, they each do their own object tracking on their own instances.
Suppose the record changes between DC1 observing it and and DC2 observing it. In this case, the record will not only have 2 different instances, but those different instances will have different values. It can be very challenging to express business logic against such a moving target.
You should definately retire the DataContext after the UnitOfWork, to protect yourself from stale instances of records.
Normally you should use one context for one logical unit of work. So have a look at the unit of work pattern, ex. http://dotnet.dzone.com/news/using-unit-work-pattern-entity
Of cause there is some overhead in creating a new DataContext each time. But its a good practice to do as Ludwig stated: One context per unit of work.
Its using connection pooling so its not a too expensive operation.
I also think creating a new DataContext each time is the correct way but this link explains different approaches for handling the data context. Linq to SQL DataContext Lifetime Management
I developed a wrapper component that uses an interface like:
public interface IContextCacher {
DataContext GetFromCache();
void SaveToCache(DataContext ctx);
}
And use a wrapper to instantiate the context; if it exists in cache, it's pulled from there, otherwise, a new instance is created and pushed to the Save method, and all future implementations would get the value from the getter.
Depending on the type of application would be the actual caching mechanism. Say for instance, an ASP.NET web application. This could store the context in the items collection, so its alive for the request only. For a windows app, it could pull it from some singleton collection. It could be whatever you wanted under the scenes.