Stelios
Stelios

Reputation: 340

in DDD ,how viewmodel can reuse domain model behavior?

I am not sure but as long i read about ddd, domain model should never leave the application layer.. if that is true then how viewmodels can reuse behavior of domain model?

Assume the following invoice model in ddd perspective

  public class Invoice
{
    public int Id { get; set; }

    public int CustomerID { get; internal set; }

    public void ChangeCustomer(Customer customer)
    {
        if (customer.IsActive == false)
            throw new Exception("Inactive customers cannot be used");

        CustomerID = customer.Id;
        //other properties change also that need to be reflected to the user interface
    }
}

And now lets have the invoice ViewModel attempt #1. Going with this idea i have no issues to reuse domain behavior, but the domain layer must be referenced to the UI Project in this case(WPF). But is here where my fears appear that we should not use domain layer outside of application layer

 public class InvoiceVMOption1 : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyUI(string PropertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }
    Invoice underlinesource;

    public InvoiceVMOption1(Invoice underlinesource)
    {
        this.underlinesource = underlinesource;
    }

    public int InvoiceID { get => underlinesource.Id; }
    public int CustomerID
    {
        get => underlinesource.CustomerID;
        set
        {
            try
            {
                //This is a very simple example. in reality when changing customer other properties of the domain change also.
                var customer = new CustomerService().Get(value);
                underlinesource.ChangeCustomer(customer);
                NotifyUI(nameof(CustomerID));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                throw;
            }

        }
    }

}

And now lets have Invoice ViewModel option #2 Going with this idea, it means application service is responsible to construct the viewmodel and give it to the UI and then UI give back viewmodel >convert to domain > update throught repository

   /// <summary>
/// I like more this idea as it decouple viewmodel from domain layer
/// The problem here is how i can reuse the logic of changing the customer since domain model is not referenced
/// </summary>
public class InvoiceVMOption2 : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyUI(string PropertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }

    private int invoiceid;
    public int InvoiceID
    {
        get => invoiceid;
        set
        {
            invoiceid = value;
            NotifyUI(nameof(InvoiceID));
        }
    }

    private int customerid;
    public int CustomerID
    {
        get => customerid;
        set
        {
            //user select a customer from combobox binding with his id
            //here we need to let the user whenever  any of the validation that exists in domain model invoice will fail when changing customer.
            //nothing will save yet
            //after user finish this viewmodel will be sent to application layer(service) convert it to domain and update through repository
            //Problem is, how i can know if customer will fail to change without writing same code validation from domain?
            customerid = value;
            NotifyUI(nameof(customerid));
        }
    }
}

Upvotes: 2

Views: 1428

Answers (1)

Subhash
Subhash

Reputation: 3270

The View Model is a one-way street. It is only meant to construct a data structure suited to the UI from the domain representation.

Each change at the UI is better modeled as a separate Command (if you are using CQRS) or a different API that calls a specific Application Service (if you are using core DDD).

By choosing to model each change, you represent the domain more accurately in your code. If you were to return the same view model with modifications to the data structure, you are hiding the intent of these changes. The flow pattern is also closer to CRUD because you are simply transferring data to the backend to be persisted.

Upvotes: 5

Related Questions