I have a WCF service, which has a method for updating a EF entity. The update method works just fine but looks ugly. I think due to some EF design I have to manually set the change tracker state to Modified
or Deleted
or Added
. The update method in the server side looks like this:
public Event UpdateEvent(Guid sessionID, Event _event)
{
Session session = IFSHelperClass.CheckSession(sessionID);
try
{
using (IFSDB ifsdb = new IFSDB())
{
ifsdb.Events.Attach(_event);
ifsdb.ObjectStateManager.ChangeObjectState(_event, System.Data.EntityState.Modified);
// mark the modified and added items
// for the navigation property 'EventPersons'
foreach (var p in _event.EventPersons)
{
if (p.ChangeTracker.State == IFSEntities.ObjectState.Added)
ifsdb.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Added);
if (p.ChangeTracker.State == IFSEntities.ObjectState.Modified)
ifsdb.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Modified);
}
// since the deleted items will not be available in the
// navigation property, delete them manually from the
// ChangeTracker object.
if (_event.ChangeTracker.ObjectsRemovedFromCollectionProperties.Count > 0)
{
var personsToDelete = _event.ChangeTracker.ObjectsRemovedFromCollectionProperties.Where(t => t.Key == "EventPersons").Select(t => t.Value)
.FirstOrDefault()
.ToList();
foreach (EventPerson p in personsToDelete)
{
ifsdb.EventPersons.Attach(p);
ifsdb.EventPersons.DeleteObject(p);
}
}
// save all changes and accept them
ifsdb.SaveChanges();
_event.AcceptChanges();
foreach (var p in _event.EventPersons)
p.AcceptChanges();
return _event;
}
}
catch (Exception ex)
{
Logger.LogError("UpdateEvent()", ex.Message, ex.ToString(), session.User.UserID);
throw ex;
}
}
As you can see, II iterate through the navigation property items to check for updates or deletes and mark them manually.
Is this the way? or am I doing something ugly here?
1 Answer 1
You shouldn't expose entities in WCF service. Every change in entity will cause WCF webservice change and incompatibility for existing consumers. I would create decicated data transfer objects for WCF webservice and use library like Automapper to handle property mapping.
EF entities often contain various properties (example: creation date, creator info), that shouldn't be modified, but when you expose whole entities, you allow this, which in future may cause security issues.
Small example (without Automapper):
public class EventDTO
{
public int Id { get; set; }
public DateTime EventDate { get; set; }
public string Title { get; set; }
}
In webservice class:
public Event UpdateEvent(Guid sessionID, EventDTO eventDTO)
{
using (IFSDB ifsdb = new IFSDB())
{
var event = ifsdb.Events.First(item => item.Id == eventDTO.Id);
event.EventDate = eventDTO.EventDate;
event.Title = eventDTO.Title;
ifsdb.SaveChanges();
}
}