3

Can we use List<ValueObject> inside entity? or we should use them as List<entity>?

When I use 'List<Discount>' inside my 'Product' entity class, entity framework creates a 'Discount' table with a generated column id.

Is it OK that i have defined Discount as List of value objects? When a value object is used as a list, is it better to use it as an entity with its identity?

The second question is about updating 'List<Discont>' inside entity. how can I update this value object list inside its entity( add,remove discount)? thanks

  • 2
    DDD people - always want other to follow their principles rather than the opposite. Let say you don't use EF Core, how would you store your list of "value objects" in relational database? When you realize that, you'll see why EF Core creates table (and each table must have primary key). For more info about the closest EF Core term (which is different from DDD), see [Collections of owned types](https://learn.microsoft.com/en-us/ef/core/modeling/owned-entities#collections-of-owned-types) – Ivan Stoev Jan 15 '22 at 15:57
  • @IvanStoev Thanks for posting the link. I have used OwnsMany(). But this shadow property, does not violate the rule of using value objects? In this case, should I update this value object list via the shadow property 'id'? – Shohreh Mortazavi Jan 15 '22 at 17:27
  • @IvanStoev In this way, I can add, remove or update the lists through this property! it violates the immutability of Value Object and its dependence on the owner. it's true? if not, how can i update the valueobject list? thanks – Shohreh Mortazavi Jan 15 '22 at 17:28
  • 2
    What I was trying to say is that DDD concepts, Value Objects etc. are not EF Core concern. EF Core entities (owned or not) represent the *data model*, not domain model. There are no "value object"s there - everything is entity. If you want to store/load your things from database using EF Core w/o violating your principles, then create separate models and use the EF Core data model to load/persist your domain entities. – Ivan Stoev Jan 15 '22 at 17:39
  • 1
    It's increasingly important to mention the database you're working in when asking EF questions. I can imagine that support for lists of value types could once be added to the Cosmos db provider, as it already supports lists of primitive types. But I assume you're targeting a relational database. – Gert Arnold Jan 16 '22 at 12:55

1 Answers1

3

As mentioned in the comments by @Ivan Stoev, your domain model is not your database model. You need to model your domain in an object-oriented way with, ideally, no regard for the database. BTW, having some identifier in a Value Object does not make it an Entity. An Entity would, however, always require a unique identifier within that entity set but an identifier isn't the defining factor to make a class an entity (that would be whether it has its own lifecycle).

In the real world one would need to be pragmatic about the general guidance. For instance, if you need an identifier of sorts for your value object then that is fine. However, it may be that there is already something there that may be used. In an OrderItem one would use the ProductId since there should only be a single item for each product. In your Discount scenario perhaps there is a DiscountType where only unique discount types are permitted. On the point of mutable value objects, the reason a value object is usually not mutable is that it represents a particular value. You would never change 10 since that would be another value. It would seem that one would be changing 10 to, say, 15 when you need 15 but, in fact, that 15 is another value object. Again, one would need to be pragmatic and in many circumstances we end up using a Value Object that isn't as primitive as a single value so it may make sense to alter something on the value object. An order item is certainly not an entity but one would need to change the Quantity on the item every-so-often. Well, that may be another discussion around Quote/Cart vs Order but the concepts are still applicable.

On another note, I tend to nowadays define any "value object" that exists only within an aggregate as a nested class within the aggregate. I would not have Order and OrderItem classes but instead an Item class within the Order class... Order.Item. That is a design choice though but I thought I'd mention it.

Eben Roux
  • 12,983
  • 2
  • 27
  • 48
  • Exactly the response I was looking for. I have seen development going wrong when analysts fail to clearly communicate the fact that some entity is the "root" and a related collection should be treated just as a "value object". From the DDD perspective, "value object" decisions should not be made based on the need for the technical (surrogate) key but on the business key. RDBMS enforces its rules and sometimes it's tricky to design around them, but it's good to keep RDBMS stuff from leaking into the domain model, as realistically possible. – JustAMartin Jul 28 '22 at 09:55