17

Value objects do not have identity. ORM needs identity to update the database.

How to trick ORM?

(Marking Id for value object as internal won't work because ORM lives in a different assembly and moving it to the same assembly is not acceptable).

Thanks in advance.

Shooresh
  • 105
  • 1
  • 11
Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195

6 Answers6

55

When Eric Evans talks about "entities have identity, Value Objects do not", he's not talking about an ID column in the database - he's talking about identity as a concept.

VOs have no conceptual identity. That doesn't mean that they shouldn't have persistence identity. Don't let persistence implementation cloud your understanding of Entities vs VOs.

See my post here.

Community
  • 1
  • 1
Vijay Patel
  • 17,094
  • 6
  • 31
  • 35
  • But i would like to show that lack of conceptual identity in code. Btw, i've seen that post before. – Arnis Lapsa Jun 05 '09 at 12:43
  • 1
    To clarify your requirement: you want to hide the ID property on your VO object, but you need the ORM to see the ID property? Two questions: 1) Can your ORM access private/internal fields? (like NHibernate) 2) How much benefit do you get by 'hiding' the VO's ID property? – Vijay Patel Jun 05 '09 at 13:03
  • Forgot to mention - i am using NHibernate... So - how to do it with NHibernate? – Arnis Lapsa Jun 28 '09 at 21:58
  • As an idea, you could try using Explicit Interface Implementations (see http://blog.briandicroce.com/2007/11/13/explicit-iterface-members-implementation-in-c). Create an interface that with the ID property, then implement the ID property explicitly on your entity class. I've not tried it myself - let me know if it works! – Vijay Patel Jun 30 '09 at 08:21
5

Personally I have the Id field in the value object - I treat it as another attribute of the value object (such as name, location etc).

It may not be true DDD but it works for me.

TWith2Sugars
  • 3,384
  • 2
  • 26
  • 43
  • 3
    I don't think there's a problem with that at all. Eric Evan's got everybody's head spinning around because it's easy to talk about concepts without giving an example. – Pepito Fernandez Nov 16 '12 at 22:11
  • The id field in the value object then according to DDD does not uniquely identify your value object. It is just another attribute value like the others. – acearch May 15 '19 at 12:02
5

As far as my understanding of DDD goes value objects are just a way to partition your entities. If a value object should be stored with an ID in the database it's not a value object.

Example:

The domain model looks like this (C#):

public class Customer : Entity
{
    public Guid CustomerID { get; }

    public string LastName { get; set; }

    public Address HomeAddress { get; set; }
}

public class Address : ValueObject
{
    public string Street { get; set; }

    public string City { get; set; }

    public string ZipCode { get; set; }
}

The corresponding database table would look something like this (Pseudo-SQL):

CREATE TABLE Customers
(
    CustomerID,

    LastName,

    HomeAddress_Street,

    HomeAddress_City,

    HomeAddress_ZipCode,
)

To store the addresses in a seperate table you would make it an entity which has an ID.

Albic
  • 3,559
  • 4
  • 22
  • 25
  • 5
    But then the domain model is just 1:1 of the database, the address can still be a value object and still have a separate table. – TWith2Sugars Jun 05 '09 at 08:30
  • 1
    No, it is not a 1:1 of the Database. You have a Customer class and an Adress class (which is the value object). In NHibernate, a value object is mapped as a component. As soon as you have an entity which needs an Id, it is no longer a value object. – Frederik Gheysels Jun 05 '09 at 08:39
  • 8
    But if you need to save the address in a table it will require an id by the database. Just because the database requires an id doesn't mean the object is instantly an entity. – TWith2Sugars Jun 05 '09 at 08:51
  • 1
    Hopefully this question ma provide more information: http://stackoverflow.com/questions/679005/how-are-value-objects-stored-in-the-database – TWith2Sugars Jun 05 '09 at 08:52
  • In this case - how to "hide" that id of VO. I`m not looking for way to completely get rid of it, cause then i wouldn`t be able to store VO data in another table. – Arnis Lapsa Jun 05 '09 at 12:46
  • Make it private and have a function called "GetPersistantData()" that returns it? – TWith2Sugars Jun 05 '09 at 12:52
  • Data normalization should have nothing to do with Model Entities and Value Objects. Albic's solution discards that a Value Object shouldn't have its own table, which is incorrect. Your NHibernate mapping should take care of how you persist your VO. – Pepito Fernandez Nov 16 '12 at 22:08
0

You have 2 options:

  • Save the Value Object in the same Aggregate Root table
  • Separate table using the Aggregate Root as the ID

For your example, something like:

public class Customer : Entity
{
    public Guid CustomerID { get; }
    public string LastName { get; set; }
    public Address HomeAddress { get; set; }
}

public class Address : ValueObject
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }
}

Option 1 (Pseudo-SQL):

​CREATE​ ​TABLE​ Customer (
      // aggregate root
​     customerId ​int​ ​NOT​ ​NULL​,
      lastName VARCHAR(30),

      // value object
      street VARCHAR(100),
      city VARCHAR(50),
      zip VARCHAR(10)
​     ​CONSTRAINT​ PK_Customer ​PRIMARY​ ​KEY​ (customerId)
​   )

Option 2 (Pseudo-SQL):

// aggregate root
CREATE​ ​TABLE​ Customer (
​   customerId ​int​ ​NOT​ ​NULL​,
    lastName VARCHAR(30)
    CONSTRAINT​ PK_Customer ​PRIMARY​ ​KEY​ (customerId)
    )

// value object
CREATE​ ​TABLE​ Address (     
​     customerId ​int​ ​NOT​ ​NULL​, // same ID from Customer

​     street VARCHAR(100),
      city VARCHAR(50),
      zip VARCHAR(10)
      ​CONSTRAINT​ PK_Address ​PRIMARY​ ​KEY​ (customerId)
    )
  • Then you can create a toDomain(sqlResult) function to convert the query result in your domain object
  • Try to use one-table approach by default
acneto
  • 51
  • 5
0

All the options for persisting value objects mentioned in the previous answers - such as flatting the value object properties as columns of the entity table they belong to or persisting them in a separate table by including a unique id for the data model - are valid and well explained. And of course those options are usually applicable independently of the specific underlying database technology which is a great plus.

But I think it is at least worth to mention some other options which in many cases can be sufficient and easy to implement:

Store value objects in JSON representation

It depends on your technology constraints of course but nowadays many databases as well as ORM solutions even provide built-in support for JSON representation. Some even including search options. If you don't expect a huge amount of items you can even use this approach for lists of value objects inside entities by persisting this list as JSON collection of objects directly in the entity table.

Alternatively to JSON there are of course other formats supported (such as plain text or XML) but from my experience I find JSON to be most comfortable.

Use a document-based storage solution

It might also be worth to mention that choosing a document based-database technology - such as MongoDB - also provides new options for persisting domain model entities as it at allows to persist an aggregate as an entire document including all its child entities and/or value objects.

Andreas Hütter
  • 3,288
  • 1
  • 11
  • 19
0

An VO belongs to an Entity. We will use Entity's ID(business ID) to track the VO.

An VO may also contains other Entities/VOs, it just represent the OO, encapsulation. Take an example, E-R, 1:N, We can use Union Table to persist it.

Focus on the business, not those concepts.