Udostępnij za pośrednictwem


Update an entity in Repository Pattern

Look around the web. You will find no Update method in the repository patterns for entity framework implementations published. There are different flavors of retrieves, mark for insertions an deletions but no update implementation. And curiously this is the most painful. There are 2 options that you have. But to explain both, I will start off with the repository design. We can get into a discussion about the pattern in case anyone is interested, all you have to do is instigate me by posting a comment.

 

So now your IRepository here has some generic functions :

---

    /// <summary>
    /// Return all instances of type T.
    /// </summary>
    /// <returns></returns>
    IEnumerable<T> All();

    /// <summary>
    /// Return all instances of type T that match the expression exp.
    /// </summary>
    /// <param name="exp"></param>
    /// <returns></returns>
    IEnumerable<T> FindAll(Func<T, bool> exp);

    /// <summary>Returns the single entity matching the expression. Throws an exception if there is not exactly one such entity.</summary>
    /// <param name="exp"></param><returns></returns>
    T Single(Func<T, bool> exp);

    /// <summary>Returns the first element satisfying the condition.</summary>
    /// <param name="exp"></param><returns></returns>
    T First(Func<T, bool> exp);

    /// <summary>
    /// Mark an entity to be deleted when the context is saved.
    /// </summary>
    /// <param name="entity"></param>
    void MarkForDeletion(T entity);

    /// <summary>
    /// Create a new instance of type T.
    /// </summary>
    /// <returns></returns>
    T CreateInstance();

    /// <summary>Persist the data context.</summary>
    void SaveAll();

---

These generic functions, if you notice, does not contain an update function. Now the 2 options that you have that I have talked about, are

Option 1: Do not take care of your updates in the provider. Now this is simple. Do all the updates in the logical layer that calls the data provider. Something like

---

                    Events dbEvent = null;
                    IEnumerable<Events> dbEvents = this.DataProvider.All<Events>(eve => eve.EventID.Equals(communityEvent.EventID));
                    if (dbEvents != null && dbEvents.Count() == 1)
                    {
                        dbEvent = dbEvents.SingleOrDefault();
                    }
                    else
                    {
                        throw new ApplicationException(MADConstants.GENERIC_DATA_ERROR);
                    }
                    dbEvent.DateModified = communityEvent.DateModified;
                    dbEvent.Description = communityEvent.Description;
                    dbEvent.EventEndDate = communityEvent.EventEndDate;
                    dbEvent.EventName = communityEvent.EventName;
                    dbEvent.EventStartDate = communityEvent.EventStartDate;
                    dbEvent.IsApproved = communityEvent.IsApproved;
                    dbEvent.LastModifiedBy = communityEvent.LastModifiedBy;
                    dbEvent.NoOfRatings = communityEvent.NoOfRatings;
                    dbEvent.Organizer = communityEvent.Organizer;
                    dbEvent.ParticipatedBy = communityEvent.ParticipatedBy;
                    dbEvent.RatedBy = communityEvent.RatedBy;
                    dbEvent.Rating = communityEvent.Rating;
                    dbEvent.Sessions = communityEvent.Sessions;
                    this.DataProvider.SaveAllChanges();

---

The second option which i feel is most elegant is this:

---

/// <summary>
        /// Updates
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entityName"></param>
        /// <param name="entity"></param>
        public void Update<T>(string entityName, T entity)
        {           
            this.context.AttachTo(entityName, entity);
        }

---

So all you have to do now is to call the functions like this

---

DataProvider.Update<Customer>(“Customer”, customer);

DataProvider.SaveAllchanges();

---

The third option is a little complex. Please refer to the diagram above, the task repositories that you will implement must contain the update function like this:

public void Update(Customer customer)

{
    context.Attach(customer) ; //Custom extensor method
    context.SaveChanges();
}

This means you have all your Task Repositories that know the type of your entity. So a CustomerRepository would know that it is handling Customer Types and hence will take Customer as a parameter to the Update Method. This is because Attach method requires an argument that is of type System.Data.Objects.DataClasses.IEntityWithKey. Which means it will not accept type T because this does not have the entity key or the primary key on the basis of which it will know which entity / row to update in the database.

The purpose of the third option is that all interaction with the database that is specific to a particular entity can be handled in the Task Repositories.

Comments

  • Anonymous
    March 18, 2009
    The comment has been removed