so I stumbled upon a weird thing just now. I have a test which changes the until
date of a workingsite
to yesterday like so:
using (var db = new ApplicationDbContext())
{
var empFromDb = db.Employees.Include(x => x.WorkingSites).First(x => x.Id == _employeeId);
empFromDb.WorkingSites.Add(workingSiteToEnd);
db.SaveChanges();
//Act
ServiceFactory.CreateEmployeeService().EndWorkingSitePeriod(workingSiteToEnd);
//Assert
var workingSiteFromDb = db.WorkingSites.First(x => x.Id == workingSiteToEnd.Id);
Assert.AreEqual(DateTime.Now.AddDays(-1).Date, workingSiteFromDb.WorksUntil.Date);
}
In this test my assert fails and the until
hasn't changed for the object workingSiteFromDb
, yet in my code I do change it and save changes to the database. note : my database did update! I checked inside the database and the date is altered correctly.
Now I didn't know what was going on and so I stopped the using
right after the first savechanges
and opened it again right before I call workingSiteFromDb
.
If I do this, it works.
Note that I use another using
within the EndWorkingSitePeriod
method.
How come my database does update but the object only updates when I use a second using
?
This is the EndWorkingSitePeriod
method:
public void EndWorkingSitePeriod(int workingSiteId)
{
using (var db = new ApplicationDbContext())
{
var workingSiteFromDb = db.WorkingSites.Include(x => x.Employee).First(x => x.Id == workingSiteId);
workingSiteFromDb.EndPeriod();
db.SaveChanges();
}
}
The workingSite.EndPeriod
just sets the UntilDate
to DateTime.Now.AddDays(-1)
First, you're obtaining workingSiteToEnd
somewhere and adding it to context, created in 1st line of your sample. Then, you're saving the changes ( workingSiteToEnd
now in the database and in the context).
Then, you're creating the second context in EndWorkingSitePeriod
method. Using that context, you're obtaining new workingSiteFromDb
instance (it doesn't relate to workingSiteToEnd
from above). You're modifying it, and saving changes.
Now, you're trying to test the changes you've made, but original workingSiteToEnd
is still present in context. This means, that when you'll try to load it from database again, context, during materialization process, will look up for entity with the same key in its local cache, will find it, and will return existing entity, which is original , unchanged workingSiteToEnd
(you can compare references, they'll be equal).
When you're closing using
block right after first SaveChanges
, and then creating new one, you're creating new context, which will load new instance for workingSiteFromDb
, and the test will pass.
Do not nest usings of the same DbContext. Instead, if you need to use the same context in called method, pass it with parameter, eg:
using (var db = new ApplicationDbContext())
{
var empFromDb = db.Employees.Include(x => x.WorkingSites).First(x => x.Id == _employeeId);
empFromDb.WorkingSites.Add(workingSiteToEnd);
db.SaveChanges();
//Act
ServiceFactory.CreateEmployeeService().EndWorkingSitePeriod(workingSiteToEnd, db);
//Assert
var workingSiteFromDb = db.WorkingSites.First(x => x.Id == workingSiteToEnd.Id);
Assert.AreEqual(DateTime.Now.AddDays(-1).Date, workingSiteFromDb.WorksUntil.Date);
}
private void EndWorkingSitePeriod(int workingSiteId, ApplicationDbContext db)
{
var workingSiteFromDb = db.WorkingSites.Include(x => x.Employee).First(x => x.Id == workingSiteId);
workingSiteFromDb.EndPeriod();
db.SaveChanges();
}
// if you need it public, then use this too
public void EndWorkingSitePeriod(int workingSiteId)
{
using (var db = new ApplicationDbContext())
{
EndWorkingSitePeriod(workingSiteId, db);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.