DDD, value objects and ORM

前端 未结 5 1909
情书的邮戳
情书的邮戳 2020-12-14 09:56

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 bec

相关标签:
5条回答
  • 2020-12-14 10:25

    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.

    0 讨论(0)
  • 2020-12-14 10:33

    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.

    0 讨论(0)
  • 2020-12-14 10:44

    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.

    0 讨论(0)
  • 2020-12-14 10:45

    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
    0 讨论(0)
  • 2020-12-14 10:49

    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.

    0 讨论(0)
提交回复
热议问题