Using Linq To SQL to update a record from a MVC3 ViewModel
I'm trying to update a record in a database with the values in a ViewModel via Linq To SQL. I had it working but it has since stopped (more on this later).
I have a Customers domain object mapped to a table. I don't need all the fields so I use AutoMapper to map it to a ViewModel (CustomerEditVM) that has a subset of the Customer fields. I do this in my service layer:
public CustomerEditVM GetCustomerEditVMById(int custId)
{
var domainCustomer = _repository.GetCustomerById(custId);
Mapper.CreateMap<Customer, CustomerEditVM>();
CustomerEditVM customer = Mapper.Map<Customer, CustomerEditVM>(domainCustomer);
return customer;
}
I send the CustomerEditVM ViewModel to my view and the user edits the record. In my service layer I map it back to a Customer object and call the Update method in my repository:
public void SaveCustomer(CustomerEditVM customer)
{
Mapper.CreateMap<CustomerEditVM, Customer>();
Customer newCust = Mapper.Map<CustomerEditVM, Customer>(customer);
_repository.Update(newCust);
}
Here is my repository and Update method:
namespace AuctionAdmin.Models.Repositories
{
public interface ICustomerRepository
{
Customer GetCustomerById(int custId);
void Update(Customer customer);
}
public class CustomerRepository : ICustomerRepository
{
p开发者_开发知识库rivate AuctionAdminDataContext _dataContext;
public CustomerRepository()
{
_dataContext = new AuctionAdminDataContext();
}
public Customer GetCustomerById(int custId)
{
var customer = _dataContext.Customers.SingleOrDefault(c => c.CustomerID == custId);
return customer;
}
public void Update(Customer customer)
{
_dataContext.Customers.Attach(customer);
_dataContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer);
_dataContext.SubmitChanges();
}
}
}
The Update used to work fine but now fails with this error:
Unable to refresh the specified object. The object no longer exists in the database.
I'm not sure why this worked so well before and now doesn't but clearly I'm not using Linq to update the database properly. How should I be doing this?
Thanks
So my understanding is that Automapper wasn't really designed to work this way. It flattens objects like you are doing to get your view model but it doesn't really do things the other way. I believe this is by design because Jimmy & Crew are using more of a command pattern with messaging to save things back into the database.
However, I know that doesn't solve your problem. So here are a few things.
With Linq2Sql You need to pull the object out, then update it, then save it. This is because linq2sql is tracking the changes of the object. However, between requests you no longer have the linq2sql object.
public void SaveCustomer(CustomerEditVM customer)
{
//Get the customer from repo
var domainCustomer = _repository.GetCustomerById(customer.Id);
Mapper.CreateMap<CustomerEditVM, Customer>();
Customer newCust = Mapper.Map<CustomerEditVM, Customer>(domainCustomer);
_repository.Update(newCust);
}
However, that most likely won't work because of the way linq2sql and automapper work. Even if the mapping does work, linq2sql might not show that changes have been made to the object. You are going to be better off mapping this by hand.
Also, there is really no such thing as Update in Linq2Sql.
public void Update(Customer customer)
{
_dataContext.Customers.Attach(customer);
_dataContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer);
_dataContext.SubmitChanges();
}
All you need to do is get the object from linq2sql update it and call SubmitChanges(); on the _dataContext. It takes care of it for you. I have seen some repository interfaces include a Update method but it doesn't do anything in a Linq2Sql implementation. Also, its probably not the best idea to call SubmitChanges in the update method as you may want to update may items then submit all the changes at once, which is kind of the purpose of submitchanges (ie unit of work)
精彩评论