Does Entity Framework create new a connection to the database on creating a new instance of DbContext ?
Agree with the DavidG, No it's doesn't create a connection at that point.
Connection are only persisted when SaveChanges() is called
Any changes made to your entities, be it updates, inserts or deletes, are only persisted to the database when the DbContext.SaveChanges() method is called. If a DbContext instance is disposed before its SaveChanges() method was called, none of the inserts, updates or deletes done through this DbContext will be persisted to the data store.
So take this code as an example:
var context = new MyContext();
var cars = context.Cars.Where(c => c.TopSpeed > 100);
var carList = cars.ToList(); //Connection will probably happen here
Where is a connection initiated? There's actually 2 possibilities. Generally there will only ever be a connection created on the last line. Instantiating a context doesn't have any side effects and the middle line is using deferred execution so doesn't need a connection yet.
However, you may find that the second line will cause a connection to be created, this will happen when your app spins up for the first time and Entity Framework needs to go and confirm that your database matches what it thinks it should be. You can disable this by disabling the initialiser, for example:
Database.SetInitializer<MyContext>(null);
How about writing to the database? Well, you have something similar going on, but this time the only time a connection is needed is when you call SaveChanges:
var context = new MyContext();
var ferarri = new Car { Name = "Ferarri", TopSpeed = 170 };
context.Cars.Add(ferarri);
context.SaveChanges(); //Connection will probably happen here
Is that all? Well no, you will also get a new connection when you start a transaction:
//Database connection will be opened here
using (var transaction = context.Database.BeginTransaction())
{
var cars = context.Cars.Where(c => c.TopSpeed > 100);
var carList = cars.ToList();
}
Related
I have an application in which I verify the following behavior: the first requests after a long period of inactivity take a long time, and timeout sometimes.
Is it possible to control how the entity framework manages dispose of the objects? Is it possible mark some Entities to never be disposed?
...in order to avoid/improve the warmup time?
Regards,
The reasons that similar queries will have an improved response time are manifold.
Most Database Management Systems cache parts of the fetched data, so that similar queries in the near future will be faster. If you do query Teachers with their Students, then the Teachers table will be joined with the Students table. This join result is quite often cached for a while. The next query for Teachers with their Students will reuse this join result and thus become faster
DbContext caches queried object. If you select a Single teacher, or Find one, it is kept in local memory. This is to be able to detect which items are changed when you call SaveChanges. If you Find the same Teacher again, this query will be faster. I'm not sure if the same happens if you query 1000 Teachers.
When you create a DbContext object, the initializer is checked to see if the model has been changed or not.
So it might seem wise not to Dispose() a created DbContext, yet you see that most people keep the DbContext alive for a fairly short time:
using (var dbContext = new MyDbContext(...))
{
var fetchedTeacher = dbContext.Teachers
.Where(teacher => teacher.Id = ...)
.Select(teacher => new
{
Id = teacher.Id,
Name = teacher.Name,
Students = teacher.Students.ToList(),
})
.FirstOrDefault();
return fetchedTeacher;
}
// DbContext is Disposed()
At first glance it would seem that it would be better to keep the DbContext alive. If someone asks for the same Teacher, the DbContext wouldn't have to ask the database for it, it could return the local Teacher..
However, keeping a DbContext alive might cause that you get the wrong data. If someone else changes the Teacher between your first and second query for this Teacher, you would get the old Teacher data.
Hence it is wise to keep the life time of a DbContext as short as possible.
Is there nothing I can do to improve the speed of the first query?
Yes you can!
One of the first things you could do is to set the initialize of your database such that it doesn't check the existence and model of the database. Of course you can only do this when you are fairly sure that your database exists and hasn't changed.
// constructor; disables initializer
public SchoolDBContext() : base(...)
{
//Disable initializer
Database.SetInitializer<SchoolDBContext>(null);
}
Another thing could be, if you already have fetched your object to update the database, and you are sure that no one else changed the object, you can Attach it, instead of fetching it again, as is shown in this question
Normal usage:
// update the name of the teacher with teacherId
void ChangeTeacherName(int teacherId, string name)
{
using (var dbContext = new SchoolContext(...))
{
// fetch the teacher, change the name and save
Teacher fetchedTeacher = dbContext.Teachers.Find(teacherId);
fetchedTeader.Name = name;
dbContext.SaveChanges();
}
}
Using Attach to update an earlier fetched Teacher:
void ChangeTeacherName (Teacher teacher, string name)
{
using (var dbContext = new SchoolContext(...))
{
dbContext.Teachers.Attach(teacher);
dbContext.Entry(teacher).Property(t => t.Name).IsModified = true;
dbContext.SaveChanges();
}
}
Using this method doesn't require to fetch the Teacher again. During SaveChanges the value of IsModified of all properties of all Attached items is checked. If needed they will be updated.
I would like to be able to iterate through every row in an entity table without holding every row in memory. This is a read only operation and every row can be discarded after being processed.
If there is a way to discard the row after processing that would be fine. I know that this can be achieved using a DataReader (which is outside the scope of EF), but can it be achieved within EF?
Or is there a way to obtain a DataReader from within EF without directly using SQL?
More detailed example:
Using EF I can code:
foreach (Quote in context.Quotes)
sw.WriteLine(sw.QuoteId.ToString()+","+sw.Quotation);
but to achieve the same result with a DataReader I need to code:
// get the connection to the database
SqlConnection connection = context.Database.Connection as SqlConnection;
// open a new connection to the database
connection.Open();
// get a DataReader for our table
SqlCommand command = new SqlCommand(context.Quotes.ToString(), connection);
SqlDataReader dr = command.ExecuteReader();
// get a recipient for our database fields
object[] L = new object[dr.FieldCount];
while (dr.Read())
{
dr.GetValues(L);
sw.WriteLine(((int)L[0]).ToString() + "," + (string)L[1]);
}
The difference is that the former runs out of memory (because it is pulling in the entire table in the client memory) and the later runs to completion (and is much faster) because it only retains a single row in memory at any one time.
But equally importantly the latter example loses the Strong Typing of EF and should the database change, errors can be introduced.
Hence, my question: can we get a similar result with strongly typed rows coming back in EF?
Based on your last comment, I'm still confused. Take a look at both of below code.
EF
using (var ctx = new AppContext())
{
foreach (var order in ctx.Orders)
{
Console.WriteLine(order.Date);
}
}
Data Reader
var constr = ConfigurationManager.ConnectionStrings["AppContext"].ConnectionString;
using (var con = new SqlConnection(constr))
{
con.Open();
var cmd = new SqlCommand("select * from dbo.Orders", con);
var reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader["Date"]);
}
}
Even though EF has few initial query, both of them execute similar query that can be seen from profiler..
I haven't tested it, but try foreach (Quote L in context.Quotes.AsNoTracking()) {...}. .AsNoTracking() should not put entities in cache so I assume they will be consumed by GC when they out of the scope.
Another option is to use context.Entry(quote).State = EntityState.Detached; in the foreach loop. Should have the similar effect as the option 1.
Third option (should definitely work, but require more coding) would be to implement batch processing (select top N entities, process, select next top N). In this case make sure that you dispose and create new context every iteration (so GC can eat it:)) and use proper OrderBy() in the query.
You need to use an EntityDataReader, which behaves in a way similar to a traditional ADO.NET DataReader.
The problem is that, to do so, you need to use ObjectContext instead of DbContext, which makes things harder.
See this SO answer, not the acepted one: How can I return a datareader when using Entity Framework 4?
Even if this referes to EF4, in EF6 things work in the same way. Usually an ORM is not intended for streaming data, that's why this functionality is so hidden.
You can also look at this project: Entity Framework (Linq to Entities) to IDataReader Adapter
I have done this by pages.
And cleaning the Context after each page load.
Sample:
Load first 50 rows
Iterate over them
Clean the Context or create a new one.
Load second 50 rows
...
Clean the Context = Set all its Entries as Detached.
This is my first post :) I'm new to MVC .NET. And have some questions in regards to Entity Framework functionality and performance. Questions inline...
class StudentContext : DbContext
{
public StudentContext() : base("myconnectionstring") {};
public DbSet<Student> Students {get; set; }
...
}
Question: Does DbSet read all the records from the database Student table, and store it in collection Students (i.e. in memory)? Or does it simply hold a connection to this table, and (record) fetches are done at the time SQL is executed against the database?
For the following:
private StudentContext db = new StudentContext();
Student astudent = db.Students.Find(id);
or
var astudent = from s in db.Students
where s.StudentID == id)
select s;
Question: Which of these are better for performance? I'm not sure how the Find method works under-the-hood for a collection?
Question: When are database connections closed? During the Dispose() method call?
If so, should I call the Dispose() method for a class that has the database context instance? I've read here to use Using blocks.
I'm guessing for a Controller class get's instantiated, does work including database access, calls it's associated View, and then (the Controller) gets out of scope and is unloaded from memory. Or the garbase collector. But best call Dispose() to do cleanup explicitly.
The Find method looks in the DbContext for an entity which has the specified key(s). If there is no matching entity already loaded, the DbContext will makes a SELECT TOP 1 query to get the entity.
Running db.Students.Where(s => s.StudentID == id) will get you a sequence containing all the entities returned from a SQL query similar to SELECT * FROM Students WHERE StudentID = #id. That should be pretty fast; you can speed it up by using db.Students.FirstOrDefault(s => s.StudentID == id), which adds a TOP 1 to the SQL query.
Using Find is more efficient if you're loading the same entity more than once from the same DbContext. Other than that Find and FirstOrDefault are pretty much equivalent.
In neither case does the context load the entire table, nor does it hold open a connection. I believe the DbContext holds a connection until the DbContext is disposed, but it opens and closes the connection on demand when it needs to resolve a query.
I'm using .NET4.5/EF5 and have created the model from an existing database.
I'm using the following code:
Order currentOrder = new Order();
using (var db = new ILSEntities())
{
try
{
Event currentEvent = db.Events.OrderByDescending(u => u.EventID).FirstOrDefault();
currentOrder.Event = currentEvent;
db.Orders.Add(currentOrder);
db.SaveChanges();
And I'm seeing that a duplicate record is being created of the Event object I find, which is not what I wanted to happen.
I've read a lot of posts relating to similar problems, but where the context of the two participants in the foreign key relationships are different. Here, I'm saving with the same context I use to find one, and the other object is new.
I've also tried:
currentOrder.Event.EventID = currentEvent.EventID;
but that fails as well as I get an EF validation error telling me it needs values for the other members of the Event object.
I've also tried specifically setting the EntityState of the object being duplicated to Detached, Modified etc. after adding the Order object but before SaveChanges without success.
I'm sure this is a basic problem, but it's got me baffled
In my understanding, both parent and child objects have to be in the context before you assign any relationship between them to convince the entity framework that an entity exists in the database already. I guess you are trying to add new Order object to Database, to add new object you should be using AddObject method, Add() method is used to establish relation between entitties. In your code, currentOrder is not in the context. Try to hook it in the same context and then assign a relation. Your code should look like this :
Order currentOrder = new Order();
using (var db = new ILSEntities())
{
try
{
Event currentEvent = db.Events.OrderByDescending(u => u.EventID).FirstOrDefault();
db.Orders.Attach(currentOrder); //attach currentOrder to context as it was not loaded from the context
currentOrder.Events.Add(currentEvent);//establish relationship
db.ObjectStateManager.ChangeObjectState(currentOrder, EntityState.Added);
db.SaveChanges();
}
}
OK, I did in the end figure this out, and it was my fault.
The problem was that the Order object is FK'd into another table, Shipments, which is also FK'd into Events. The problem was that it was the Event reference in the Shipment object that was causing the new record. The solution was to let EF know about these relationships by adding them all within the same context.
The code assembling the object graph was spread over a number of webforms and the responses here made me take a step back and look at the whole thing critically so whilst no one of these answers is correct, I'm voting everybody who replied up
using(DataContext db = new DataContext ())
{
var result = db.SomeTable.ToList();
return result;
}
Problem is after i have returned the result, the connection is closed and because its closed, it crashes when i am trying to access any of the child elements. That happens because with lazy loading set to True ( default ) it never loads the child relations before they are used and i start using them AFTER the connection is closed. So how is the best way to solve this?
I have tried to turn off the lazy loading but then it didnt load any of the child relation tables.
You can always explicitly load your child collections:
var result = db.SomeTable.Include("SomeChildCollectionName")
.Include("AnotherChildCollectionName")
.ToList();
You can use the .include() method.
var result = db.SomeTable.Include("ChildEntitySet").ToList();
You can also add a result.ChildEntitySet.Load() call before returning. This is less efficient as it will result in two trips to the server. Using the .Include() method will generate a SQL Statement with a JOIN allowing only one trip to the server.