As I take my first steps with Entity Framework CTP 4 (Magic Unicorn) I realise that all isn’t quite as sweet and smooth sailing as the examples would have me believe.
What does that mean? Well for a while I’ve taken the approach that methods that make changes to the database return a Boolean which makes it easy to give simple feedback to the user, and I've combined my Save and Updates because the only difference between them is that in the case of an update the ID is known, if the ID is not known then it is a new item and it must be a save (that I've handled in the stored procedures). In the case of my DAL I'll have a method such as this:
public static Boolean Save(ToDo toDo)
{
SqlParameter[] parameters = {
new SqlParameter("@ToDoID", SqlDbType.Int, 4)
, new SqlParameter("@StaffID", SqlDbType.TinyInt, 2)
, new SqlParameter("@TaskName", SqlDbType.VarChar, 100)
, new SqlParameter("@DueDate", SqlDbType.SmallDateTime)
, new SqlParameter("@PriorityID", SqlDbType.TinyInt, 2)
, new SqlParameter("@Notes", SqlDbType.VarChar, 6000)};
parameters[0].Value = todoID == null ? parameters[0].Value = DBNull.Value : parameters[0].Value = todo.ID;
parameters[1].Value = todo.Staff.ID;
parameters[2].Value = todo.TaskName;
parameters[3].Value = todo.DueDate == null ? parameters[3].Value = DBNull.Value : parameters[3].Value = todo.DueDate;
parameters[4].Value = todo.Priority.ID;
parameters[5].Value = todo.Notes;
try
{
SqlHelper.ConnectionString(DbConnection);
SqlHelper.ExecuteNonQuery("uspSav_ToDo", parameters, out _rowsAffected);
return (_rowsAffected >= 1);
}
catch (Exception ex)
{
_log.Error(ex.ToString());
return false;
}
}
So from there I can just call my Save method and provide user feedback based on what it returns.
if (controller.Save(MyObject))
{
MessageBox.Show("the save worked");
// Other stuff…
}
else
{
MessageBox.Show("the save failed");
// Other other stuff…
}
However the examples given, for EF at least, seem to always treat the Save (create) and Update methods separately even though the examples given are pretty simple cases. The trouble is that I then have 2 nearly identical methods differing only in 1 parameter and I would prefer otherwise (I realise this may violate the Single Responsibility Principle but actually I’m not sure it does and I’m prepared to make that sacrifice for the maintainability of my code).
Initially I found I was going down that path though, 1 (public) Save method and 1 (public) Update method and what I found really worrying was that I needed to do a bunch of left right assignment stuff in my update method.
public void SaveToDo(ToDo todo)
{
context.ToDo.Add(todo);
context.SaveChanges();
}
public void UpdateToDo(ToDo updated)
{
var todo = context.ToDo.Find(updated.ID);
todo.DateCompleted = updated.DateCompleted;
todo.DateDeleted = updated.DateDeleted;
todo.DueDate = updated.DueDate;
todo.Notes = updated.Notes;
todo.Priority = updated.Priority;
todo.Staff = updated.Staff;
todo.TaskName = updated.TaskName;
todo.Version ++;
context.SaveChanges();
}
Yuk! I really didn’t like this, but I’d spent a little while Googling and hadn’t come across anything that really explained how you updated an entity using Entity Framework, even the sample Scott Gu gives in his code first development with EF4 post shows manually updating a property (but fails to address updating many properties). Then I had a lucky break in discovering the Attach method (as yet I haven tested this to see that it works but) I think it does what I want and means I don’t have to do all that tedious left-right property assignment you see in UpdateToDo above. What I’ve ended up with is this:
public void SaveOrUpdate(ToDo todo)
{
if (todo.ID != -1)
Update(todo);
else
{
context.ToDo.Add(todo);
context.SaveChanges();
}
}
private void Update(ToDo updated)
{
updated.Version++;
context.ToDo.Attach(updated);
context.SaveChanges();
}
Publically I’ve just got the single SaveOrUpdate method (I have to confess I 'borrowed’ this name from NHibernate) so now anything that’s saving something, whether it’s new and a save or existing and therefore an update all calls the same method SaveOrUpdate and if the ID is not –1 then it must be an existing record so it calls the private Update method. The Update method increments the Version property (again I’m borrowing from NH a little), then attaches the object so when I call SaveChanges my updated object is persisted for me.
If anyone has any observations on this approach I would like to hear them – it’s early days for me here so I may be re-inventing the wheel or worrying about something there’s no need for or I may even have a nice pattern, who knows… but here’s hoping Scott Hanselman picks up this post, reads it and decides to do one of his Weekly Source Code reviews on it 
56adfc2b-ecd0-4d5a-938f-ea168ee9b2dd|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: EntityFramework |
Categories: Development | EntityFramework