Skip to content
Marek Fišera edited this page Aug 7, 2015 · 1 revision

Models provides contracts for modeling domain (and anemic) models and accessing them. Each domain model implementes interface IDomainModel<TKey>, where TKey is type implementing IKey. Anemic models typically implements IModel<TKey> which adds public setter on key property.

This project distinguishes between domain and model as domain model should be all the time consistence, so business validation are placed inside and typically public property setters are repaced by methods, that modifies the object state.

On the other hand, models are designed for standard CRUD-like applications where business validations are realized by services/repositories/etc.

Instance of this TKey uniquely identifies domain model. Based on this, there interfaces for loading model by IReadOnlyRepository and saving by IRepository.

Keys

Interface IKey abstract values that uniquely identifier instance of domain model. In the most common scenario, this is realized by ID field/column, so common Int32Key with ID property is included. But advanced scenarios may include more fields and can be use-case specific, so IKey provides abstract to group thes fields together for simple and straight forward model identification.

This key can be easily serialized and transfered over the wire and on the other side deserialized by generic code, so many code lines can be abstract and reused.

Domain repositories

Domain models are designed for editing values (and optionaly showing detail of single item). With this in mind, repositories typically supports two actions, loading instance by key, and saving/creating existing/new instance.

For these purposes, there are designed to generic interfaces, one for reading only (IReadOnlyRepository), and one with supported for saving changes (IRepository which extends IReadOnlyRepository). These interfaces takes as generic arguments type of domain model and type of key.

Example repository usage

This example shows how use domain repository and model to execute command (in terms of CQRS). Command handler at first loads domain model/aggregate, executes action and stores model back to the repository.

private readonly IRepository<Reservation, Int32Key> repository;
private readonly IEventDispatcher eventDispatcher;

public ConfirmReservationCommandHandler(IRepository<Reservation, Int32Key> repository, IEventDispatcher eventDispatcher) 
{
    Ensure.NotNull(repository, "repository");
    Ensure.NotNull(eventDispatcher, "eventDispatcher");
    this.repository = repository;
    this.eventDispatcher = eventDispatcher;
}

public void Handle(ConfirmReservationCommand command)
{
    Reservation reservation = repository.Find(command.ReservationKey);
    if(reservation == null)
        eventDispatcher.Publish(new ReservationNotFoundEvent(command.ReservationKey));

    reservation.Confirm();
    repository.Save(reservation);
    eventDispatcher.Publish(new ReservationConfirmed(command.ReservationKey));
}

Example edit page for CRUD domain model

Domain models can be also in CRUD scenario. In these situations, we can implement generic page/controller for editing model.

public class EditController<TModel, TKey> : Controller
{
    private readonly IRepository<TModel, TKey> repository;

    public EditController(IRepository<TModel, TKey> repository)
    {
        Ensure.NotNull(repository, "repository");
        this.repository = repository;
    }
    
    public ActionResult Edit(TKey key)
    {
        TModel model = repository.Find(key);
        if (model == null)
            return View("NotFound", key);

        //TODO: Use optional overridable method for mapping domain model to edit view model.        
        return View(model);
    }

    [HttpPost]
    public ActionResult Edit(TModel model)
    {
        if (ModelState.IsValid)
        {
            repository.Save(model);
            return RedirectToAction("Edit", model.Key);
        }

        return View(model);
    }
}

With such edit controller, we must implement only the views (which are specific for each model).