Continuing issues with "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" using MVC3 EF4.1 - asp.net-mvc

I posted this question previously and it explains what I'm doing pretty thoroughly:
ASP.NET MVC3 and Entity Framework v4.1 with error An entity object cannot be referenced by multiple instances of IEntityChangeTracker
The problem is that this issue has resurfaced several times with the mini-cart, lost cart, checkout page, etc after I fixed this particular problem in the question above. The further issues have been related to this, but not necessarily easy to identify and took a considerable amount of time to troubleshoot, find, and fix. Rather than post my most current specific issue I'd rather find out if I'm doing something wrong in general. Either by storing the cart, which is an entity, in a Session, or a better way to detach it (detach method shown below), or is there an easier way to debug these types of issues? Here is an update to my detach method:
public void DetachCart(Cart cart)
{
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
if (cart.Customer != null)
{ objectContext.Detach(cart.Customer); }
if (cart.ShipFromAddress != null)
{
var shipFromAddress = cart.ShipFromAddress;
objectContext.Detach(cart.ShipFromAddress);
cart.ShipFromAddress = shipFromAddress;
}
if (cart.ShipToAddress != null)
{
var shipToAddress = cart.ShipToAddress;
objectContext.Detach(cart.ShipToAddress);
cart.ShipToAddress = shipToAddress;
}
if (cart.Lines != null && cart.Lines.Count > 0)
{
List<CartLine> lines = new List<CartLine>();
foreach (var item in cart.Lines.ToList())
{
objectContext.Detach(item);
lines.Add(item);
}
cart.Lines = lines;
}
objectContext.Detach(cart);
}
Thank you for any insight you could provide me on this issue. It's been a long painful road with this one.
UPDATE
It seems that a lot of my trouble stems from the fact that CartModelBinder leaves the cart in the attached state rather than the detached state. By changing that it has eliminated my current issue and removed several places where I had to detach to avoid this issue. However, my question "is there an easier way to detach all, or a way to debug/track these issues" still stands.

There is one solution - don't use entities in your views or model binders. Use view models and convert them to entities only when you are going save data to the database. It can make your application more complex but it will save you a great amount of time when troubleshooting issues with leaked contexts, attaching and detaching.

Related

Is NonShared DbContext in MVC a bad practice?

It is an MVC application with Entity Framework Code First for the ORM and MEF as the IoC.
If I mark the DbContext with PartCreationPolicy.Shared there is an error saying the object already exists in the container every time I try to perform an edit.
But what if I simply mark the DbContext with PartCreationPolicy.NonShared so it gets created for every request?
Is there a terrible performance impact for that?
Update
Here is the code for save:
Provider IRepository<Provider>.Put(Provider item)
{
if (item.Id == Guid.Empty)
{
item.Id = Guid.NewGuid();
this.Providers.Add(item);
}
else this.Entry<Provider>(item).State = EntityState.Modified;
return item;
}
And this is the error when on Shared
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
You should definitely use PartCreationPolicy.NonShared. Everything you can read about context lifecycle management, whether it's linq to sql, entity framework, or NHibernate (sessions), will agree upon one thing: the context should be short-lived. An easy rule of the thumb is: use it for one unit of work, which means: create a context, do stuff, call SaveChanges once, dispose. Most of the times this rule works well for me.
A shared (or singleton) context is the pattern that hits performance, because the context gets bloated over time. The change tracker needs to track more and more objects, relationship fixup will get slower. And you will find yourself refreshing (re-loading) entities time and again.

Breeze BeforeSaveEntityonly only allows update to Added entities

Don't know if this is intended or a bug, but the following code below using BeforeSaveEntity will only modify the entity for newly created records (EntityState = Added), and won't work for modified, is this correct?
protected override bool BeforeSaveEntity(EntityInfo entityInfo)
{
var entity = entityInfo.Entity;
if (entity is User)
{
var user = entity as User;
user.ModifiedDate = DateTime.Now;
user.ModifiedBy = 1;
}
...
The root of this issue is that on the breeze server we don’t have any built in change tracking mechanism for changes made on the server. Server entities can be pure poco. The breeze client has a rich change tracking capability for any client side changes but when you get to the server you need to manage this yourself.
The problem occurs because of an optimization we perform on the server so that we only update those properties that are changed. i.e. so that any SQL update statements are only made to the changed columns. Obviously this isn’t a problem for Adds or Deletes or those cases where we update a column that was already updated on the client. But if you update a field on the server that was not updated on the client then breeze doesn't know anything about it.
In theory we could snapshot each entity coming into the server and then iterate over every field on the entity to determine if any changes were made during save interception but we really hate the perf implications especially since this case will rarely occur.
So the suggestion made in another answer here to update the server side OriginalValuesMap is correct and will do exactly what you need.
In addition, as of version 1.1.3, there is an additional EntityInfo.ForceUpdate flag that you can set that will tell breeze to update every column in the specified entity. This isn't quite as performant as the suggestion above, but it is simpler, and the effects will be the same in either case.
Hope this helps.
I had the same problem, and I solved that doing this:
protected override bool BeforeSaveEntity(EntityInfo entityInfo)
{
if(entityInfo.EntityState== EntityState.Modified)
{
var entity = entityInfo.Entity;
entityInfo.OriginalValuesMap.Add("ModificationDate", entity.ModificationDate);
entity.ModificationDate = DateTime.Now;
}
}
I think you can apply this easily to your case.

How to structure Entityframework DB Contexts

I haven't been able to find any answers online for this.
What are the advantages/disadvantages of using Multiple DB Contexts against using a single?
Is the below solution ok for setting related objects, (when saving to DB) (to make it more efficient, because I already have the ID, no need to fetch object)
I've heard its reccommened to use contexts like Using(MyContext c = MyContext) {}, at the moment I'm using the default MVC way, of having the context instantiated in the controller, is this ok?
Person P = new Person();
P.QuickSetCar(CarID);
db.People.Add(P);
db.saveChanges();
and
private void QuickSetCar(int CarID)
{
if(this.Car == null) {
Car C = new Car();
C.ID = ID;
this.Car = C;
}
}
Using multiple contexts is always a disadvantage unless you have no choice (e.g. your data is dispersed across multiple databases).
Almost, but you can simplify your new car initialization to:
private void QuickSetCar(int CarID) {
if(this.Car == null)
this.Car = new Car(){ ID = CarID };
}
That's fine. Just don't use more than one context for the duration of the web transaction (request/response) and don't keep it around for longer than that either.
Multiple contexts are normally only useful for very large models spread over multiple databases. If you are starting a project it is normally best to use a single context.
Your method for using IDs is fine.
Creating contexts within controllers is certainly workable but I would strongly suggest against it. This approach is often shown in demos and for basic scaffolding but in real world applications it is not a great idea. Large amounts of code will often be duplicated by instatiating and querying contexts in each controller. Also have a central repository will allow for much easier caching to improve performance.

Performance of repository pattern and IQueryable<T>

I have no idea if I'm doing this right, but this is how a Get method in my repository looks:
public IQueryable<User> GetUsers(IEnumerable<Expression<Func<User, object>>> eagerLoading)
{
IQueryable<User> query = db.Users.AsNoTracking();
if (eagerLoading != null)
{
foreach (var expression in eagerLoading)
{
query = query.Include(expression);
}
}
return query;
}
Lets say I also have a GeographyRepository that has GetCountries method, which is similar to this.
I have 2 separate service layer classes calling these 2 separate repositories, sharing the same DbContext (EF 4.1 code-first).
So in my controller, I'd do:
myViewModel.User = userService.GetUserById(1);
myViewModel.Countries = geoService.GetCountries();
This is 2 separate calls to the database. If I didn't use these patterns and tie up the interface and database, I'd have 1 call. I guess its something of a performance vs maintainability.
My question is, can this be pushed to 1 database call? Can we merge queries like this when views calls multiple repositories?
I'd say that if performance is the real issue then I'd try and avoid going back to the database altogether. I'm assuming the list returned from geoService.GetCountries() is fairly static, so I'd be inclined to cache it in the service after the initial load and remove the database hit altogether. The fact that you have a service there suggests that it would be the perfect place to abstract away such details.
Generally when asking questions about performance, it's rare that all perf related issues can be tarred with the same brush and you need to analyse each situation and work out an appropriate solution for the specific perf issue you're having.

EF4 - Self tracking entities and inheritance and eager loading

I know this has been asked before in several ways but none of the answers seem applicable to me - or correct - or current, so I'll try again.
I have a large model with several intstances of inherited entities. One example is a Timetable that contains a collection of TimetableEvents. There are several sub-types of TimetableEvent, such as an InterviewTimetableEvent, BreakTimetableEvent and an ExercisetimeTableEvent. ExerciseTimetableEvent has a relationship to an Exercise entity.
I need to use self-tracking entities as I'm using a WCF back end to serve up data to several WPF clients in a stateless fashion.
So, I need to eager load everything and I thought that self-tracking entities would automatically do this but it appears they dont.
So, to get a timetable I need to do something like this:
var tt = (from s in ESSDataContainer.Timetables
.Include("TimetableEvents")
where s.TimetableId == timetableid
select s).FirstOrDefault();
This will give me the TimetableEvents but not the Exercises that are related to the ExerciseTimetableEvents. Ive tried the following (and several other suggestions) without luck:
var tt = (from s in ESSDataContainer.Timetables
.Include("TimetableEvents")
.Include("ExerciseTimetableEvents.Exercise")
where s.TimetableId == timetableid
select s).FirstOrDefault();
Is there a solution to this?
If not I'll go back to normal context tracking and connect to the database from a local container rather than using WCF.
Cheers
It's a bit tricky, but possible:
var tt = (from s in ESSDataContainer.Timetables
where s.TimetableId == timetableid
select new
{
TimeTable = s,
Events = s.TimeTableEvents,
Exercise = s.TimeTableEvents.OfType<ExerciseTimetableEvents>()
.Select(ett => ett.Exercise)
}).Select(s => s.TimeTable)
.AsEnumerable()
.FirstOrDefault();
Clear as mud, but, hey: No magic strings! Also, it has the advantage that it actually works....
There is a Proposal for this issua at Microsoft Connect:. If you think this worthy you can vote for it.

Resources