1

A lot of discussions, like this and this, go with RICH DOMAIN MODEL

and there are 2 strong reason about amenic, like 1 and 3:

Now let's say that I need to make sure that I need to validate that the product exists in inventory and throw exception if it doesn't.

so there is a question: If we don't need an object to be dependent on ISomeRepository like service, can we just make this:

public void Order.AddOrderLine(IEnumerable<Product> products, Product product)
{
    if(!prosucts.Contains(product))
         throw new AddProductException

    OrderLines.Add(new OrderLine(product));
}

and call it like this:

Order.AddOrderLine(ISomeRepository.GetAll(), product);
Community
  • 1
  • 1
Roar
  • 2,117
  • 4
  • 24
  • 39
  • 1
    Are you asking if this is valid C# code? Or if it is preferable to some of the other options? The answer to the first question can be tested by compiling it. The answer to the second question is pretty subjective. – Mark Hildreth Dec 17 '13 at 19:12
  • 1
    Perhaps this is a question for CodeReview stack exchange. – MattDavey Dec 17 '13 at 19:21

2 Answers2

1

It sounds like there's a missing concept in your domain here. I'd think about introducing some kind of StoreInventory entity, such that products move out of the inventory and into an order (this is called 'picking' in many commerce domains).

interface StoreInventory
{
    IEnumerable<Product> AvailableProducts { get; }
    Product PickProduct(guid productId); // This doesn't have to be an Id, it could be some other key or a specification.
}

void Order.AddOrderLine(StoreInventory inventory, Product product)
{
    if (!inventory.AvailableProducts.Contains(product.Id))
        throw new AddProductException();

    var item = inventory.Pick(product);
    OrderLines.Add(new OrderLine(item);
}

This would seem to be more closely aligned to reality to me. But as always in DDD, only your domain experts can tell you how things are supposed to flow.

This also seems more extensible in the future, for example with this model it would be easy to introduce multiple stores - each with their own inventory.

MattDavey
  • 8,897
  • 3
  • 31
  • 54
  • First, exposing IEnumerable is dangerous, because it has chance of pulling all products from DB. Second, the way IStoreInventory will be implemented will turn into normal repository. So it is not much different from what I suggested. – Euphoric Dec 17 '13 at 19:54
  • @Euphoric I wouldn't consider the `StoreInventory` to be a repository, I'd make it a first class domain entity in its own right, possibly a value object in the Store aggregate. – MattDavey Dec 17 '13 at 22:34
  • *"First, exposing IEnumerable is dangerous, because it has chance of pulling all products from DB."* You're making a whole bunch of assumptions there. Firstly you're assuming that the class is connected to the database at all, which it isn't. And even if it was, you're assuming that it's using Entity Framework, LinqSQL, NHibernate or something similar. Lots of assumptions, none of them correct. – MattDavey Jan 15 '14 at 17:52
  • *"the way IStoreInventory will be implemented will turn into normal repository"* Not at all, the `StoreInventory` would be a value object in the `Store` aggregate. Therefore you would have a `StoreRepository` to fetch a `Store` object along with its inventory. – MattDavey Jan 15 '14 at 17:53
  • How can it be a value object, when it doesn't contain any attributes, the "data" is computed and it is interface whose concrete implementation exists outside the domain (most probably as part of data-access layer). Also, assuming it is a value object, you should not pass it as parameter, but have it associated to order. Also the code you have written will enumerate over all products and assuming all products are in the DB, you just pulled all the products into the memory. – Euphoric Jan 15 '14 at 18:45
  • I'm really not talking about some pseudo DDD on top of an Entity Framework data model. As I said the StoreInventory has absolutely nothing to do with the database. It's really hard to understand what I'm talking about when you're so hung up on the Entity Framework way of doing things (which has very little to do with DDD). – MattDavey Jan 16 '14 at 08:31
  • I'm talking about fact, that checking whetever product is available will be some kind of query against a database. Doesn't matter if it is EF or SQL. This is why it has to be implemented as repository. It is much safer assumption than assuming you can have all products in a memory acessible through IEnumerable. – Euphoric Jan 16 '14 at 08:42
  • You're making assumptions again based on one very naive way of implementing DDD. My answer has **nothing to do with the database**. *"checking whetever product is available will be some kind of query against a database"* **not true**. *" it has to be implemented as repository."* **not true**. *"assuming you can have all products in a memory acessible through IEnumerable."* You **can**, although this seems impossible to you because EF does not allow you to have the concept of bounded contexts. And without bounded contexts you're not really doing DDD at all. – MattDavey Jan 17 '14 at 11:00
0

If you read about DDD, you would see that Repository is core concept of DDD. In DDD, repository is part of domain and says what kind of behavior the domain requires from it's persistence to work. In your case, you could simply pass the repository into the method and have the method pull the necessary data.

public void Order.AddOrderLine(ISomeRepository repo, Product product)
{
    if(!repo.ProductExists(product))
         throw new AddProductException

    OrderLines.Add(new OrderLine(product));
}

// call it like
Order.AddOrderLine(someRepository, product);

I think the problem of your confusion is that repository, or more precisely, it's abstraction, is often tied to the persistence itself. Which is actually misconception caused by misunderstanding of the whole pattern. Correct repository consists of 2 parts: the abstraction, usually represented by interface, which defines what kind of operations the domain requires from the persistence. And the concrete implementation, that implements those operations over used persistence technology.

Euphoric
  • 12,645
  • 1
  • 30
  • 44