views:

872

answers:

3

I am creating a Web application using ASP.NET MVC, and I'm trying to use domain-driven design. I have an architecture question.

I have a WebControl table to store keys and values for lists so they can be editable. I've incorporated this into my business model, but it is resulting in a lot of redundant code and I'm not sure it belongs there. For example, in my Request class I have a property called NeedType. Because this comes from a list, I created a NeedType class to provide the values for the radio buttons. I'm showing just one example here, but the form is going to have probably a dozen or so lists that need to come from the database.

[edit, to clarify question] What's a better way to do this? Are these list objects really part of my domain or do they exist only for the UI? If not part of the domain, then they don't belong in my Core project, so where do they go?

public class Request : DomainObject
{
   public virtual int RequestId { get; set; }
   public virtual DateTime SubmissionDate { get; set; }
   public virtual string NeedType { get; set; }
   public virtual string NeedDescription { get; set; }
   // etc.
}

public class NeedType : DomainObject
{
    public virtual int NeedTypeId { get; set; }
    public virtual string NeedTypeCode { get; set; }
    public virtual string NeedTypeName { get; set; }
    public virtual int DisplayOrder { get; set; }
    public virtual bool Active { get; set; }
}

public class RequestController : Controller
{
    private readonly IRequestRepository repository;

    public RequestController()
    {
        repository = new RequestRepository(new HybridSessionBuilder());
    }

    public RequestController(IRequestRepository repository)
    {
        this.repository = repository;
    }

    public ViewResult Index(RequestForm form)
    {
        ViewData.Add("NeedTypes", GetNeedTypes());
        if (form == null)
        {
            form = new RequestForm();
            form.BindTo(repository.GetById(125));
        }
    }

    private NeedType[] GetNeedTypes()
    {
        INeedTypeRepository repo = new NeedTypeRepository(new HybridSessionBuilder());
        return repo.GetAll();
    }
}
+1  A: 

If it comes from a list, then I'm betting this is a foreign key. Don't think about your UI at all when designing your domain model. This is simply a case where NeedType is a foreign key. Replace the string NeedType with a reference to an actual NeedType object. In your database, this would be a reference to an id.

When you're building your list of NeedType choices, you simply need to pull every NeedType. Perhaps keeping it cached would be a good idea if it doesn't change much.

Stuart Branham
I understand what you are saying (there are considerations related to migrating data from a previous version that caused me to decide to store the text rather than the ID). But because this table exists solely to support making the lists on the form editable, I wasn't sure it belonged in the domain model.
Leslie
+3  A: 

Create a seperate viewmodel with the data you need in your view. The Model in the M of MVC is not the same as the domainmodel. MVC viewmodels are dumb DTO's without behaviour, properties only. A domain model has as much behaviour as possible. A domain model with get;set; properties only is considered an anti-pattern called "anemic domain model". There are 2 places where most people put the viewmodels: in the web layer, close to the views and controllers, or in a application service layer.

Edit:

When you only need to display a list of all needtypes in the database and one request in your view, I would indeed create one viewmodel with the request and the list of needtypes as properties. I don't think a call to multiple repositories in a controller is a smell, unless you have a larger application and you might want a seperate application service layer that returns the whole viewmodel with one method call.

I think it might also be a good idea to follow the advise of Todd Smith about value object. When the needtypes can be added or edited by users at runtime, needtype should be an entity. When the needtypes are hardcoded and only changed with new releases of the project, needtype should be a value object and the list of needtypes could be populated by something like NeedType.GetAll() and stored in the database by adding a column to the request table instead of a seperate needtype table.

Paco
An "anemic domain model" isn't always a bad thing. For example my validation rules for a domain object might change depending on the process they're used in. By having my validation rules separate from my model it makes the model anemic yet more configurable.
Todd Smith
A domain model is not just about entities. Factories, value-objects, repositories, domain-services (not application services like an authentication-service) are also part of the domain. I use validation in different places and for different purposes, but that does not mean that I have to make my domain model anemic.
Paco
It's about object-oriented programming versus procedural programming.
Paco
I do have a viewmodel, notice that the controller references a RequestForm object, not a Request object. The calls to other repositories are a smell that tells me I don't have this set up right. Do I make NeedTypes[] part of the Request object? This doesn't quite make sense to me because the Request object doesn't care about all the need types it isn't, only about the type it is. I only need NeedType[] to populate the lists on the view.
Leslie
@Leslie: see edit
Paco
@Paco Thanks for your help
Leslie
+1  A: 

Your NeedType looks like a value object to me. If it's read-only data then it should be treated as a value object in a DDD architecture and are part of your domain.

A lot of people run into the "omg so much redundancy" issue when dealing with DDD since you're no longer using the old Database -> DataTable -> UI approach.

Todd Smith
This is how I have it set up. I was more worried about the redundancy in the sense that every list will have the exact same five properties. I could make them inherit from a base type, but that base type is about lists on the view, not the domain really. I thought there might be another way to set this up.
Leslie