views:

24

answers:

1

I've reached a bit of a problem in my app and I'm not sure how best to resolve it.

I'm using Linq to Sql and I have a domain object which wraps the Linq object so I don't directly expose Linq objects to my front end.

So I have something like:

class MyOrder : IOrder 
{
    Order _order; // this is the Linq entity

    public MyOrder(Order o) { ... }

    // Mapping between my domain Item class and the Linq class
    public void SetItemDetails(IItem item)
    {
        _order.Item = new Item
        { 
            StockCode = item.StockCode,
            Price = item.Price
        };                
    }

    // ...and the other way
    public IItem GetItemDetails()
    {
        return new MyItem
        {
            StockCode = _order.Item.StockCode,
            Price = _order.Item.Price
        }
    }
}

This has worked fine so far as all my domain objects are immutable so I effectively have only Get and Set actions, not Update actions.

But I've now reached a point where I need an updatable property.

I want to do something like the following in my MVC front end:

[AcceptVerbs(HttpVerbs.Post)]
public void SetCustomerDetails(int id, FormCollection form) 
{
    IOrder = _repository.GetOrderById(id);

    ICustomer customer = IOrder.GetCustomerDetails(); 

    // customer will already have some, but not all, fields set

    UpdateModel(customer);

    // now customer has all fields set

    _repository.SubmitChanges();

    // ... and we haven't actually updated anything!
}

The problem should be obvious - because of the mapping in the MyOrder class, updating MyOrder.Customer doesn't actually change any of the properties on the underlying Linq objects, so it's not possible to update the database using this pattern.

I'm hoping someone could suggest a solution to this problem that still keeps the API relatively intuitive.

For example, I could probably do something like the following (not actually tested but I think it should work):

ICustomer customer = IOrder.GetCustomerDetails(); 
UpdateModel(customer);
IOrder.SetCustomerDetails(customer)

... but to me that's hopelessly unintuitive and really not a suitable solution.

Note that I can't make ICustomer immutable as then I can't use the MVC UpdateModel method. I think this is kinda where the whole problem is stemming from.

A: 

you shouldn't be exposing your domain object to your views either, you need another intermediary (ViewModel, as MS likes you to call them).

You don't want to be calling UpdateModel on your domain objects as its open to abuse.

Instead, create a ViewModel that contains only the data you want to send to that particular view/be updated by that view.

Then you can UpdateModel on that, then call the relevant domain methods, something like:

class UpdateCustomerDetailsViewModel
{
    string OrderId;
    string DeliveryAddress;
}

public void SetCustomerDetails(int id, FormCollection form) 
{
    var viewModel = new UpdateCustomerDetailsViewModel();
    UpdateModel(viewModel );

    IOrder = _repository.GetOrderById(id);

    ICustomer customer = IOrder.GetCustomerDetails(); 

    customer.UpdateDetails(viewModel.DeliveryAddress);

    _repository.SubmitChanges();
}
Andrew Bullock
I'm not really convinced by this approach. You end up with the same problem - because you can't use UpdateModel directly on your model, any large form is going to end up with an overly long action method as you have to update each model property manually.
fearofawhackplanet
then use something like automapper. If you update your model directly, whats to stop me sending a doctored POST request that updates properties you didnt want me to in that action?
Andrew Bullock