Force Entity Framework to return a new instance - entity-framework

We have a scenario in our code when only a few properties of an entity are allowed to be changed. To guarantee that, we have code similar to this:
public void SaveCustomer(Customer customer)
{
var originalCustomer = dbContext.GetCustomerById(customer.Id);
if (customer.Name != originalCustomer.Name)
{
throw new Exception("Customer name may not be changed.");
}
originalCustomer.Address = customer.Address;
originalCustomer.City = customer.City;
dbContext.SaveChanges();
}
The problem with this code is that the call to dbContext.GetCustomerById does not always gives me a new instance of the Customer class. If the customer already has been fetched from the database, Entity Framework will keep the instance in memory and return it on every subsequent call.
This leads us to the actual problem - customer and originalCustomer may refer to the same instance. In that case, customer.Name will be equal to originalCustomer.Name and we will not be able to detect if it differs from the database.
I guess the same problem exists with most other ORMs as well, because of the identitymap design pattern.
Any ideas how this can be solved? Can I somehow force EF to always give me a new instance of the customer class?
Or should we refactor the code instead? Does anyone know of any good design patterns for this scenario?

you can try by detaching the entity from the context, this will remove all the references to the context (as well as the identitymap behaviour).
So, before passing the Customer to your method you can detach it:
yourContext.Detach(customer);

Related

Entity Framework not updating existing related entity

I have a project which uses Entity Framework extensively. And it all works fine.
However, there is one update that I am trying to make and it does not update, nor is an error thrown.
The basic process is that I take an existing entity, work with it to create a new (and different type) of entity. The new entity saves just fine, but the existing one does not.
Typically when I have encountered this, it means that the entity is not attached to the context. However, it is, and I have tried attaching it again as well as "Adding" it, but I have had no luck.
if (fileRowEntity != null)
{
this.Context.FileRowEntities.Attach(fileRowEntity);
fileRowEntity.FileRowStatusId = (int)FileRowStatus.Converted;
fileRowEntity.EdiDocument = ediDocument;
}
ediDocument.InsertedDate = DateTime.Now;
ediDocument.EdiDocumentGuid = Guid.NewGuid();
ediDocument.DocumentMetatdata = null;
this.Context.EdiDocuments.Add(ediDocument);
var count = this.Context.SaveChanges();
The ediDocument is saved, but the fileRowEntity is not saved.
I am tearing my hair out trying to figure this out. I have tried a second explicit save on the fileRowEntity but it comes back with zero changes saved:
if (fileRowEntity != null)
{
fileRowEntity.EdiDocumentId = ediDocument.EdiDocumentId;
fileRowEntity.Column100 = "X";
this.Context.FileRowEntities.Attach(fileRowEntity);
count = this.Context.SaveChanges();
}
count is always zero, and the database is not updated.
I don't know what else to try to debug this.
Attaching an entity to a context does not mark it as modified.
In your case, the presumption is that the context instance where you are calling SaveChanges() on, is not the same that retrieved the fileRowEntity object, so it doesn't know that it was modified (or what was modified).
When a DbContext retrieves an object from the store, it stores a copy of its original values (unless you used AsNoTracking() on that query), and whenever it detects changes by a call to DetectChanges(), which you can make explicitly, but the normal DbContext implementation will call it by itself at many points), it'll store the new object values. If there are differences between those, the next call to SaveChanges will update the entity in the store/database.
When you attach an entity but don't mark it as modified, it doesn't know anything has changed, so you can explicitly mark the entity as modified:
Using Context.Entry(fileRowEntity).State = EntityState.Modified; should tell EF that your entity was modified, and it'll generate the update command when you call SaveChanges() for the whole entity (it'll send all the field values in the UPDATE SQL). Note that doing this also attaches the entity if it was not attached to the context (no need to attach it and then set its state).
You can also mark only the properties that were modified (or change the entity OriginalValues), this way your query will be optimized (it'll only update the fields that have actually changed). It's a bit cumbersome to track those changes yourself, but if you need that extra optimization, it's worth a shot (personally, unless there's a critical load on the database server and every bit counts, I wouldn't do this, but your choice)
There is a second reason for the above described behavior: This code will turn off change tracking:
Context.Configuration.AutoDetectChangesEnabled = false;
After I found this had been set in the constructor and removed it, all worked as expected.

EF 4.0 IsAttachedTo extension method and error An object with the same key already exists

I was getting an error
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
After i googled it i found IsAttachedTo extension method there:
Is is possible to check if an object is already attached to a data context in Entity Framework?
here is my code:
foreach (string s in types)
{
Subscription subscription = new Subscription { Id = Int32.Parse(s) };
if (service.repository._context.IsAttachedTo(subscription))
service.repository._context.Detach(subscription);
service.repository._context.AttachTo("Subscriptions", subscription); //error here
horse.Subscriptions.Add(subscription);
}
But when the subscription with the same key appeared in the foreach loop the extension method IsAttachedTo returning false every time, it is does not detect that there is already such entity attached. And in result i am getting the same error:
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
Why it is could be?
What can i do to fix that?
I have little code review for you because your sample code scares me.
You probably read a lot about fancy design patterns and layered architectures and you started to use them yourselves. Unfortunately you missed the main point. What the hell is this?
service.repository._context.XXX
Why do you bother with any service layer or repository layer if they don't encapsulate their logic? Why do you expose repository on the service? Nobody should know about service internal implementation? Even worse why do you expose context on the repository? That spoiled the whole point of the repository!
There are a lot of supporting rules for writing high quality object oriented code. One of this rules is called Law of Demeter. You don't have to follow each rule, you also don't have to follow rules all the time but in case of layered architecture this law is a must.
If you have three layers A -> B -> C the layer A can call methods on the layer B but it doesn't know about C and it cannot reach its methods. If it can, it is not a new layer but it is the same layer as B and the layer A doesn't need to call it through B, it can call it directly.
In your example you have just exposed D to A because A is current layer, B is service, C is repository and D is context.
One more points about your code. There are well known naming conventions. These conventions are not about I like this and you like that but about the fact that framework you are using follow these conventions strictly so using another one to mix your naming convention with framework naming convention make your code look messy.
I'm sorry, If this was only some example code to make your code structuring clear. I just needed to describe how wrong this code is.
Now to your real problem. The method you have referenced from the related question will not work in your case. I think it will work only if you load the subscription from the database. The reason is that the referenced method uses EntityKey (either internally or directly) to get the entity from context but your new entity doesn't have the entity key yet. I expect that calling TryGetObjectStateEntry for your entity will always return Detached. Entity key it is created during attaching or you have to build it manually.
If you want some IsAttachedTo method try this:
public bool IsAttachedTo<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.Any(e => e.Id == entity.Id);
}
And make sure that your entity implements helper interface
public interface IEntity
{
int Id { get; }
}
But to be able to detach attached entity you will need:
public T GetAttached<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.SingleOrDefault(e => e.Id == entity.Id);
}
You will have to detach instance returned from this method.
Anyway I would start to think why do you need that for the first place because it looks like your architecture has another wrong concept. Why don't you use attached entities directly? If you don't use them why do you even keep the context with them?
It's likely that IsAttachedTo does not compare by the key (Id) but by object identity. Because you create a new Subscription for every item in the loop the objects are all different instances.
Since you seem to have objects with same Id in your types collection but in the end only want to add one object per key into the context you can perhaps make your life easier by filtering out the duplicates in the first place:
var distinctTypes = types.Distinct();
foreach (string s in distinctTypes)
{
Subscription subscription = new Subscription { Id = Int32.Parse(s) };
service.repository._context.AttachTo("Subscriptions", subscription);
horse.Subscriptions.Add(subscription);
}
This way there should be only one object per key which gets attached to the context.

Force EF 4.1 Code First to See an Attached entity as Modified

All the examples I've found refer to a class called ObjectContext, which doesn't appear to exist in CTP5. I must stress at this point, CTP5 is my first exposure to the Entity Framework.
I have a disconnected POCO that I have attached to my DbContext. SaveChanges does not pick up the change though, how I tell my context to update that entity?
_context.Users.Attach(user);
// The user has been replaced.
_context.SaveChanges();
// The change is not saved.
What am I doing wrong?
Update 12/01/2011
Might be obvious to most, but as a first time user of EF, it didn't occur to me that attaching an object that was already attached would clear the previous state. This caused me a lot of pain. But I wanted to use the Repository pattern in a very generic way, a way which didn't care if the object was already attached or had been freshly created as the result of ASP.NET MVC binding. So I needed an UpdateUser method, and I've attached it below.
public User UpdateUser(User user) {
if (_context.Entry(user).State == EntityState.Detached) {
_context.Users.Attach(user);
_context.Entry(user).State = EntityState.Modified;
}
return user;
}
The method obviously assumes that the object exists in the data store in some fashion, it's called UpdateUser after all. If the object is already attached, you will benefit from the object's previous state, which in turn will allow for an optimised update to the DB. However, if the object was not attached, the method forces the whole thing to become dirty.
Seems obvious now, wasn't before. Hope it helps someone.
Rich
When you Attach an entity, it goes to Unchanged state (it has not been changed since it attached to the context). All you need to is to explicitly change the Entity State to Modified:
_context.Users.Attach(user);
_context.Entry(user).State = System.Data.Entity.EntityState.Modified;
_context.SaveChanges();
For the sake of completeness, you can access the ObjectContext by casting the DbContext to IObjectContextAdapter:
((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.ChangeObjectState(user, EntityState.Modified);
Morteza's method is much cleaner though and gets my vote.
I believe u do not need to attach the entity before u call modified. simply setting to modified will do the job.
if (_context.Entry(user).State == EntityState.Detached)
{
_context.Entry(user).State = EntityState.Modified;
}

Entity Framework Validation & usage

I'm aware there is an AssociationChanged event, however, this event fires after the association is made. There is no AssociationChanging event. So, if I want to throw an exception for some validation reason, how do I do this and get back to my original value?
Also, I would like to default values for my entity based on information from other entities but do this only when I know the entitiy is instanced for insertion into the database. How do I tell the difference between that and the object getting instanced because it is about to be populated based on existing data? Am I supposed to know? Is that considiered business logic that should be outside of my entity business logic?
If that's the case, then should I be designing controller classes to wrap all these entities? My concern is that if I deliver back an entity, I want the client to get access to the properties, but I want to retain tight control over validations on how they are set, defaulted, etc. Every example I've seen references context, which is outside of my enity partial class validation, right?
BTW, I looked at the EFPocoAdapter and for the life of me cannot determine how to populate lists of from within my POCO class... anyone know how I get to the context from a EFPoco Class?
This is in reply to a comment I left. Hopefully this answers your question, Shimmy. Just comment, and I will shorten it or remove it if it doesn't answer your question.
You will need both INotifyPropertyChanging and INotifyPropertyChanged interfaces to be implemented on your class (unless it is something like an entity framework object, which I believe implements these internally).
And before you set a value to this property, you will need to raise NotifyPropertyChanging.PropertyChanging event, using the name of the property in PropertyChangingEventArgs constructor.
And after you set this value you need to raise NofityPropertyChanged.PropertyChanged event, again using the name of the property this is being raised in PropertyChangedEventArgs constructor.
Then you have to handle the PropertyChanging and PropertyChanged events. In the PropertyChanging event, you need to cache the value. In the PropertyChanged event, you can compare and throw an exception.
To get the property from PropertyChanging/PropertyChanged event args, you need to use relfection.
// PropertyName is the key, and the PropertyValue is the value.
Dictionary <string, object> propertyDict = new Dictionary<object, object>();
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanging(sender As object, e As PropertyChangingEventArgs) Handles Foo.PropertyChanging
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it checks if e.PropertyName already exists.
propertyDict.Add(e.PropertyName, propertyValue);
} // End PropertyChanging() Event
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanged(sender As object, e As PropertyChangedEventArgs) Handles Foo.PropertyChanged
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it makes sure e.PropertyName exists.
object oldValue = propertyDict(e.PropertyName);
object newValue = propertyValue;
// No longer needed.
propertyDict.Remove(e.PropertyName);
if (/* some condition */)
{
try {
preventRecursion = true;
info.SetValue(oldValue, null);
Throw New Exception();
} finally {
preventRecursion = false;
} // End try
} // End if
} // End PropertyChanging() Event
Notice how I am using PreventRecursion, which is a boolean I forgot to add above these methods? When you reset the property back to its previous value, these events will be recalled.
tl;dr
Now you could derive a single event which inherits from INotifyPropertyChanged, but uses an argument which holds an Object representing the previous value as well as the Property Name. And that would reduce the number of events being fired down to one, have similar functionality, and have backwards compatibility with INotifyPropertyChanged.
But if you want to handle anything before the property gets set (say the property does an irreversible change or you need to setup other properties before setting that variable, otherwise an exception will be thrown) you won't be able to do that.
Overall, this method is a very old way of doing things. I would take Poker Villian's answer and have invalid data able to be entered. But disallow saving to a database.
Entity Framework has some excellent code towards validation. You add validation to your properties via attributes. And then it takes care of the work of processing those attributes. Then you can make a property called IsValid, which calls Entity Framework specific validation. It also distinguishes both field errors (like typing in the wrong characters or having a string too long), and class errors (like having missing data or conflicting keys).
Then you can bind IsValid to controls validation, and they will display a red bubble while invalid data is entered. Or you could just implement IsValid validation yourself. But If IsValid is false, SaveChanges event would need to cancel saving.
btw. The code provided will not compile and is pseudocode only (mixing vb and c#). But I believe it is much more descriptive than c# alone--showing exactly what is being handled.
Concerning your first question, I would simply implement the changes to the associations as business logic. For example, if you add a Teacher class with multiple Student, do not add students like
aTeacher.Students.Add(new Student)
instead, create a AddStudent method
public Student AddNewStudent(string name, string studentID)
{
Student s = new Student( name, studentID);
s.Teacher = this; // changes the association
return s;
}
That way you have full control on when associations are changed. Of course that what prevents another programmer from adding a student directly? On the Student side, you can set the Teacher setter to private (and change the constructor to accept a teacher or similar). On the teacher side, how to make the Students collection non-insertable? I'm not certain... maybe transforming it in a custom collection that doesn't accept inserts.
Concerning the second part of your question, you could probably use the OnVarNameChanging events. If the EntityState is 'New' then you can apply your logic that fetches the real values.
There is also an event that fires when you save changes (OnSavingChanges?) that you could use to determine which objects are new and set some values.
But maybe the simplest solution is to always set the defaults in the constructor and they will get overwritten if the data is loaded from the DB.
Good luck
Create a factory that produces instances for you depending on your need like:
getStudent(String studentName, long studentId, Teacher teacher) {
return new Student(studentName, studentId);
}
getStudentForDBInseration(String studentName, long studentId, Teacher teacher) {
Student student = getStudent(studentName, studentId);
student = teacher;
//some entity frameworks need the student to be in the teachers student list
//so you might need to add the student to the teachers student list
teacher.addStudent(student);
}
It's a serious lack not having an AssociationChanging (that inherits from CancelEventArgs) event.
It bothers me also very much, therefore I reported this to Microsoft Connect Please vote here!
And BTW, I also think this is also stupid that the PropertyChangingEventArgs doesn't inherit CancelEventArgs, since cancelling with an exception is not always the elegant solution, besides, throwing exceptions cost more performance than calling the OnPropertyChangingEvent then check for the returned e.Cancel, so does it cost less than raising the PropertyChangingEvent, which you anyway call them both.
Also an exception can be thrown at the handler anyway instead of marking e.Cancel as true, for those who insist to go the Exception way. Vote Here.
To maybe answer part of your question or expound on ADB's answer you can user ObjectStateManager.GetObjectStateEntry to find the state of the entities and write your custom default logic.
SaveChanges is the method on the context that you can use, or SavingChanges is the event that occurs before SaveChanges is called.
You can override SaveChanges and only call base.SaveChanges if you don't want to abort the change
There is also a ObjectMaterialized event for the context.
Between the two you can stick all your validation and creation code in one location, which may be appropriate if they are complex and include values of other objects etc..

In ADO.Net Data Services how do I check if an entity is already in the context?

I have an ADO.Net Data Service that I am using to do a data import. There are a number of entities that are linked to by most entities. To do that during import I create those entities first, save them and then use .SetLink(EntityImport, "NavigationProperty", CreatedEntity). Now the first issue that I ran into was that the context did not always know about CreatedEntity (this is due to each of the entities being imported independently and a creation of a context as each item is created - I'd like to retain this functionality - i.e. I'm trying to avoid "just use one context" as the answer).
So I have a .AddToCreatedEntityType(CreatedEntity) before attempting to call SetLink. This of course works for the first time, but on the second pass I get the error message "the context is already tracking the entity".
Is there a way to check if the context is already tracking the entity (context.Contains(CreatedEntity) isn't yet implemented)? I was thinking about attempting a try catch and just avoiding the error, but that seems to create a new CreatedEntity each pass. It is looking like I need to use a LINQ to Data Services to get that CreatedEntity each time, but that seems innefficient - any suggestions?
I think you should look at the EntityState property of your entity.
Only if it is of the value EntityState.Detached than you have to add it to your context.
Do not forget the following remark:
This enumeration has a FlagsAttribute
attribute that allows a bitwise
combination of its member values.
I would create a extension method:
public static class EntityObjectExtensions
{
public static Boolean IsTracked(this EntityObject self)
{
return (self.EntityState & EntityState.Detached) != EntityState.Detached;
}
}
When trying to check whether the context was tracking the entity that I wanted to update (or add) I was pretty disapointed when I found that the context.Entites.Contains(currentItem) didn't work.
I got around it using:
if (context.Entities.Where(entities => entities.Entity == currentItem).Any())
{
this.service.UpdateObject(currentItem);
}