UpdateOrAdd method in Repository + UnitOfWork pattern - entity-framework

Is it acceptable to add UpdateOrAdd method in Repository pattern or maybe UpdateMethod with parameter 'AddIfNoExists' ?
I want to add such method to simplify using od DataServices.
For example: Client code show data in grid..then client sends all data to UpdateMethod of repository..then Repository figures out what data was added and what data was modified.

It is completely up to you how will the public interface of your repository look like. If you want single method for both inserting and updating you can of course expose it but you must correctly handle the behavior in method implementation - EF will not help you with it because it expects separate calls for inserts and updates.

I always create one method in the repository which called Add, it will add new object if it's new and will update the object if it's existing but saving or updating this not belong to the repository because the repository didn’t track state and which one new or which one existing before, this is belong to the Unit of work, this why the Unit of work pattern telling that you should track of what you've changed; otherwise, that data won't be written back into the database
So you will need to add this method in the unit of work class depending on your ORM or you DAL approach
So the Unit of work will track
New objects
Dirty objects
Delete object
And at the end you will
Commit (Save)--> add new and update existing or
Rollback

Related

What is the point of the Update function in the Repository EF pattern?

I am using the repository pattern within EF using an Update function I found online
public class Repository<T> : IRepository<T> where T : class
{
public virtual void Update(T entity)
{
var entry = this.context.Entry(entity);
this.dbset.Attach(entity);
entry.State = System.Data.Entity.EntityState.Modified;
}
}
I then use it within a DeviceService like so:
public void UpdateDevice(Device device)
{
this.serviceCollection.Update(device);
this.uow.Save();
}
I have realise that what this actually does it update ALL of the device's information rather than just update the property that changed. This means in a multi threaded environment changes can be lost.
After testing I realised I could just change the Device then call uow.Save() which both saved the data and didnt overwrite any existing changes.
So my question really is - What is the point in the Update() function? It appears in almost every Repository pattern I find online yet it seems destructive.
I wouldn't call this generic Update method generally "destructive" but I agree that it has limited use cases that are rarely discussed in those repository implementations. If the method is useful or not depends on the scenario where you want to apply it.
In an "attached scenario" (Windows Forms application for instance) where you load entities from the database, change some properties while they are still attached to the EF context and then save the changes the method is useless because the context will track all changes anyway and know at the end which columns have to be updated or not. You don't need an Update method at all in this scenario (hint: DbSet<T> (which is a generic repository) does not have an Update method for this reason). And in a concurrency situation it is destructive, yes.
However, it is not clear that a "change tracked update" isn't sometimes destructive either. If two users change the same property to different values the change tracked update for both users would save the new column value and the last one wins. If this is OK or not depends on the application and how secure it wants changes to be done. If the application disallows to ever edit an object that is not the last version in the database before the change is saved it cannot allow that the last save wins. It would have to stop, force the user to reload the latest version and take a look at the last values before he enters his changes. To handle this situation concurrency tokens are necessary that would detect that someone else changed the record in the meantime. But those concurrency checks work the same way with change tracked updates or when setting the entity state to Modified. The destructive potential of both methods is stopped by concurrency exceptions. However, setting the state to Modified still produces unnecessary overhead in that it writes unchanged column values to the database.
In a "detached scenario" (Web application for example) the change tracked update is not available. If you don't want to set the whole entity to Modified you have to load the latest version from the database (in a new context), copy the properties that came from the UI and save the changes again. However, this doesn't prevent that changes another user has done in the meantime get overwritten, even if they are changes on different properties. Imagine two users load the same customer entity into a web form at the same time. User 1 edits the customer name and saves. User 2 edits the customer's bank account number and saves a few seconds later. If the entity gets loaded into the new context to perform the update for User 2 EF would just see that the customer name in the database (that already includes the change of User 1) is different from the customer name that User 2 sent back (which is still the old customer name). If you copy the customer name value the property will be marked as Modified and the old name will be written to the database and overwrite the change of User 1. This update would be just as destructive as setting the whole entity state to Modified. In order to avoid this problem you would have to either implement some custom change tracking on client side that recognizes if User 2 changed the customer name and if not it just doesn't copy the value to the loaded entity. Or you would have to work with concurrency tokens again.
You didn't mention the biggest limitation of this Update method in your question - namely that it doesn't update any related entities. For example, if your Device entity had a related Parts collection and you would edit this collection in a detached UI (add/remove/modify items) setting the state of the parent Device to Modified won't save any of those changes to the database. It will only affect the scalar (and complex) properties of the parent Device itself. At the time when I used repos of this kind I named the update method FlatUpdate to indicate that limitation better in the method name. I've never seen a generic "DeepUpdate". Dealing with complex object graphs is always a non-generic thing that has to be written individually per entity type and depending on the situation. (Fortunately a library like GraphDiff can limit the amount of code that has to be written for such graph updates.)
To cut a long story short:
For attached scenarios the Update method is redundant as EFs automatic change tracking does all the necessary work to write correct UPDATE statements to the database - including changes in related object graphs.
For detached scenarios it is a comfortable way to perform updates of simple entities without relationships.
Updating object graphs with parent and child entities in a detached scenario can't be done with such a simplified Update method and requires significantly more (non-generic) work.
Safe concurrency control needs more sophisticated tools, like enabling the optimistic concurrency checks that EF provides and handling the resulting concurrency exceptions in a user-friendly way.
After Slauma's very profound and practical answer I'd like to zoom in on some basic principles.
In this MSDN article there is one important sentence
A repository separates the business logic from the interactions with the underlying data source or Web service.
Simple question. What has the business logic to do with Update?
Fowler defines a repository pattern as
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
So as far as the business logic is concerned a repository is just a collection. Collection semantics are about adding and removing objects, or checking whether an object exists. The main operations are Add, Remove, and Contains. Check out the ICollection<T> interface: no Update method there.
It's not the business logic's concern whether objects should be marked as 'modified'. It just modifies objects and relies on other layers to detect and persist changes. Exposing an Update method
makes the business layer responsible for tracking and reporting its changes. Soon all kinds of if constructs will creep in to check whether values have changes or not.
breaks persistence ignorance, because the mere fact that storing updates is something else than storing new objects is a data layer detail.
prevents the data access layer from doing its job properly. Indeed, the implementation you show is destructive. While the Data Access Layer may be perfectly capable of perceiving and persisting granular changes, this method marks a whole object as modified and forces a swiping UPDATE.

Domain driven design: overriding virtual methods in Domain classes

My application is broken down into several assemblies.
The MyProject.Infrastructure assembly contains all of the Domain objects such as Person and Sale as well as interfaces repositories such as IPersonRepository and ISaleRepository.
The MyProject.Data assembly contains concrete implementations of these repositories.
The repositories pull data from a database and instantiate new domain classes. For example, IPersonRepository.GetPersonByNumber(customerNumber) will read a customer from the data source, create a new Person class, populate it and return to the caller.
I'm now starting to see cases where adding some methods to my Domain classes might make sense, such as Person.UpdateAddress(address).
Is it ok to put this method on my Person class as a virtual method, and then create derived classes inside my Data layer which override those methods to provide the desired functionality?
I want to make sure I'm not going breaking any DDD conventions.
I know I also have the option of putting these methods on the repository - e.g. IPersonRepository.UpdatePersonAddress(person, address).
Person.UpdateAddress should definitely be in your domain, not in your Repository. UpdateAddress is logic and you should try to avoid logic inside your repository. If you're working with Entity framework there is no need for 'data classes'.
Most ORMs have change trackers which will persist related entities automatically when you persist the main one (provided you declared the right relations in the mapping configuration), so you don't need UpdatePersonAddress() on your Repository. Just do whatever you want to do at the object level in Person.UpdateAddress(address) without thinking about persistence, this is not the place for that.
What you need though is an object that will be called in execution context-aware code to flush changes to the persistent store when you think it's time to save these changes. It might be a Unit of Work that contains the Entity Framework DbContext, for instance.

How can I create a detached clone of an EF codefirst class for testing purposes?

I want to create an integration test which grabs an EF entity from the DB, clones it to a detached object, modifies it and then saves it back and compares it again to the original.
However, I was using AutoMapper to create the clone of the class, but it turns out this is also tracked or an alias to the original object. I need it to be completely detached from EF, and am able to do this outside of my repository class (i.e. not using any EF detach methods).
The reason for doing this is my EF class contains nested collections of other classes and EF doesn't handle persisting the whole object tree. Hence, my Update() method in my repository class handles this and I want my NUnit test to test this code. I want the test is to be able to quickly create a copy of my original class without EF tracking it.
Creating a cloned object containing current, original, or database
values The DbPropertyValues object returned from CurrentValues,
OriginalValues, or GetDatabaseValues can be used to create a clone of
the entity. This clone will contain the property values from the
DbPropertyValues object used to create it. For example:
using (var context = new UnicornsContext())
{
var unicorn = context.Unicorns.Find(1);
var clonedUnicorn = context.Entry(unicorn).GetDatabaseValues().ToObject();
}
Note that the object returned is not the entity and is not being
tracked by the context. The returned object also does not have any
relationships set to other objects.
The cloned object can be useful for resolving issues related to
concurrent updates to the database, especially where a UI that
involves data binding to objects of a certain type is being used. (See
Part 9 for more details on dealing with optimistic concurrency.)
*From http://blogs.msdn.com/b/adonet/archive/2011/01/30/using-dbcontext-in-ef-feature-ctp5-part-5-working-with-property-values.aspx
Hope it can helps others
All troubles are gone once you're using EF 5+ where they introduced AsNoTracking() method.
The line below returns an unlinked instance, so all the context won't be aware about any changes in that instance:
context.Clients.AsNoTracking().FirstOrDefault(item => item.Id == id);
If Clients has a reference to Address and you want an unlinked instance of it too, just use an Include:
context.Clients
.Include("Address").AsNoTracking()
.FirstOrDefault(item => item.Id == id);
If it is a test you can do anything and you don't have to be binded to any architectural approach like repository. Your repository probably receive context as injection so you can have access to it. Another point is that I don't believe that AutoMapper will create tracked entity.
The one way to make a copy of the class is using serialization which by default saves only public fields (Xml serialization or DataContract serialization). Serialize the object and deserialize it back to a new instance. Serialization will save the whole object graph and deserialized object graph will be detached. Just be aware that that those serializations don't likes cyclic references in object graph (navigation property from A to B and from B to A from cycles). Serialization is also too much aggresive so it can traverse the graph more deeply then you want - this can be especially dangerous in many to many relations.
The best approach is using either ICloneable interface and implement Clone or define support methods which will do different clones with required depth.
Here is another approach for clonning EntityObject based entities. It is tough code, especially part with Reflection.Emit. But this will not help you because code-first is using POCOs.

Why does updating an object only work one, particular way?

I am trying to update an object using EF4. An object is passed from the strongly-typed page to the action method and
[HttpPost]
public ActionResult Index(Scenario scenario, Person person)
{
// Some business logic.
// Update Scenario with Person information.
scenario.Person = person;
// Update the corresponding object and persist the changes.
// Note that the repository stems from the repository pattern. Contains the ObjectContext.
Scenario updateScenario = repository.GetScenario(scenario.ScenarioID);
updateScenario = scenario;
repository.Save();
}
However, the problem is that the changes do not persist when I do this. However, if I instead update every single property within the scenario individually and then persist the changes (via the Save method), everything is persisted.
I'm confused why this is happening. In my real application, there are MANY items and subobjects within a Scenario so it is not feasible to update every individual property. Can someone please help clear up what is happening and what I need to do to fix it?
In the context of your action method, you have two different objects of type Scenario. scenario points to one of the objects and updateScenario points to another one. With the line of code:
updateScenario = scenario
All you are doing is causing the updateScenario to point to the same object that scenario points to, you are not copying the values that make up the object from one to another. Essentially, your database context is aware of only 1 of the 2 instances of Scenario. The other instance of Scenario was created outside of the context and the context has not been made aware of it.
In your particular scenario you can accomplish what you want by not taking a Scenario on your parameter, and instead, pull the Scenario that you want to update from your database context and in your action method, invoke:
this.TryUpdateModel(updateScenario);
This will cause the model binder to update the property/fields on the Scenario object that your database context is aware of, and therefore will persist the changes when you call Save().
HTH

Callbacks on entity on created/updated

I would like to know when entities in a certain database table are either created or updated. The application is essentially a CMS, and I need to know when changes are made to the content so that I can reindex them for searches.
I know that the autogenerated LINQ to EF class has overridable methods for when certain fields change, but I need to know when the whole object is created/updated, not just a single field. I tried putting it in OnCreated, only to find that meant OnObjectInitialized and not OnObjectInsertedIntoDBTable xD
I did some searching and came across this link. The "Entity State" section looks like its what I want, but I'm not sure how to use this information. Where do I override those methods?
Or perhaps there is a another/better way?
(I also need to know this for another part of the system, which will send notifications when certain content is changed. I would prefer this code to execute automatically when the insert/update occurs instead of placing it in a controller and hoping hoping I always call that method.)
You need to get ObjectStateEntry(s) from the ObjectStateManager property of the ObjectContect.
var objectStateEntries = this.ObjectStateManager.GetObjectStateEntries();
This entries contain every object state you've pulled down per context and what kind of actions where performed on them.
If you are using EF4 you can override the SaveChanges method to include this functionality. I've used this technique to audit every change that occurs in the database instead of triggers.