views:

138

answers:

6

Hi all,

I have the following DB model:

**Person table**
ID    |    Name    | StateId
------------------------------
1          Joe       1
2          Peter     1
3          John      2

**State table**
ID    |    Desc
------------------------------
1          Working
2          Vacation

and domain model would be (simplified):

public class Person
{
    public int Id { get; }
    public string Name { get; set; }
    public State State { get; set; }
}

public class State
{
    private int id;
    public string Name { get; set; }
}

The state might be used in the domain logic e.g.:

if(person.State == State.Working)
    // some logic

So from my understanding, the State acts like a value object which is used for domain logic checks. But it also needs to be present in the DB model to represent a clean ERM.

So state might be extended to:

public class State
{
    private int id;
    public string Name { get; set; }

    public static State New {get {return new State([hardCodedIdHere?], [hardCodeNameHere?]);}}
}

But using this approach the name of the state would be hardcoded into the domain.

Do you know what I mean? Is there a standard approach for such a thing? From my point of view what I am trying to do is using an object (which is persisted from the ERM design perspective) as a sort of value object within my domain. What do you think?

Question update: Probably my question wasn't clear enough.

What I need to know is, how I would use an entity (like the State example) that is stored in a database within my domain logic. To avoid things like:

  if(person.State.Id == State.Working.Id)
      // some logic

or

if(person.State.Id == WORKING_ID)
// some logic
+1  A: 

It's a common practice to include an 'Unknown' element with value 0 in an enum. You can do this and use it for the New state if you really want to.

But what you are describing is business logic... setting a state after creating a new object should then happen in the business logic layer, not inside the class itself.

Gerrie Schenck
A: 

In my opion the domain layer has to be seperated from the DB model / ERM design. I had trouble understanding your final suggestion for the State class. IMHO this is not a good thing for establishing a common language which is one of the main purposes of DDD.

I would go for a simpler design. The state belongs to the Person class. I would include it in the class.

public class Person
{
    public int Id { get; }
    public string Name { get; set; }
    public PersonState State { get; set; }
}

The state itself seems to have defined values (I assume a person is an employee in your context) which don't change very often. So I would model it as enum and treat it as a data type.

enum Days {Working, Vacation};

This is a simple to understand design in my opinion. The mapping to the ERM design belongs IMHO in the persistence layer. There the enum has to be mapped to the key of the state table. This could be done using an aspect to keep the original domain model clean.

spa
+2  A: 

Your proposed structure seems fine. (Terminology digression: since State has an ID, it's not a Value Object, but rather an Entity.)

Enums are a code smell, so don't attempt to go that route. It's much more object-oriented to move the behavior into the State object using the State pattern.

Instead of having to write

if (person.State == State.Working)
    // do something...

all over your code, this would allow you to write

person.State.DoSomething();

That's much cleaner, and will allow you to add new States if need be.

Mark Seemann
Why the anonymous downvote?
Mark Seemann
question has to do with how to impliment the state pattern, its a given the asker is using state pattern.
Brian Leahy
@Brian Leahy: I don't see the State *pattern* mentioned anywhere in the question...
Mark Seemann
he's using a state objects hydrated from a db value. he's mapping state Working and state Vacation. your answer explains state pattern a bit, but not how to do the hydration... his question pertains to the hydration not the use of the pattern itself.
Brian Leahy
A: 

You want to create a factory method that will instantiate the appropriate state class needed, based on the value stored.

something like

public  static State GetStateByID( StateEnum value)
{
   if(value.Invalid)
        throw new Exception();

switch(value)
   case State.Working
        return new WorkingState();
   case State.somethingelse
         return new somethingelseState();
   case State.something
         return new somethingState();
   case State.whatever
         return new whateverState();

}

When using enums always try to use 0 as Invalid. Under the hood an enum is a value type, and an unassigned int is always 0.

It is common to use a factory, such as this, in conjunction with the state pattern.

So when you read your stored integer value from the database you can cast the int to the enum and call the factory with it to get the appropriate State object.

Brian Leahy
+2  A: 

A previous question of mine unearthed some useful links that I suspect are pertinent to your question, in particular Jimmy Bogard's discussions of Enumeration Classes.

rohancragg
+1  A: 

I personally think it's a mistake to program against IDs. Instead, I would amend your table to the following:

   **State table**
ID    |    Desc               | IsWorking  | IsVacation
-----------------------------------------------------------
1          Working                True         False
2          Vacation               False        True

I would then use these attributes to make business decisions on such as:

    public void MakeDecisionOnState(State state)
    {
        if (state.IsVacation)
            DoSomething();
        if (state.IsWorking)
            DoSomethingElse();
    }

Or by being even more clever, use the factory pattern to create the correct instance based on these attributes:

    public abstract class State
    {
        public Guid Id { get; set; }

        public string Description { get; set; }

        public abstract void DoSomething();

    }

    public class WorkingState : State
    {
        public override void DoSomething()
        {
            //Do something specific for the working state
        }
    }

    public class VacationState : State
    {
        public override void DoSomething()
        {
            //Do something specific for the vacation state
        } 
    }

    public class StateFactory
    {
        public static State CreateState(IDataRecord record)
        {
            if (record.GetBoolean(2))
                return new WorkingState { Id = record.GetGuid(0), Description = record.GetString(1) };
            if (record.GetBoolean(3))
                return new VacationState { Id = record.GetGuid(0), Description = record.GetString(1) };

            throw new Exception("Data is screwed");
        }
    }

Now you've eliminated the if/switch statement, and your code could simply be:

state.DoSomething();

The reason why I do this is that often these types of entities (or more likely value objects in DDD) can be configured by the customer, i.e. they may not want to have some of the states active in the system, or they may wish to term them something else. By programming against the attributes the customer can delete / edit the records as they please and even if that process generates new ID's it doesn't affect the system, they just need to set the attributes.

DavidMasters84