0

Suppose I am buying coffee. There are several types of coffee (A1, A2, A3), but sometimes I want to make a reference to all types of coffee (like if I had a coffee "grouped"). Considering DDD concepts, coffee A1 is different from all types of coffee, so that's their identities and I need to reference both specific and generic Coffee Entity.

I thought I could map it like:

class Coffee{ 
  private CoffeeId id;
  @NotNull
  private Code code;
  private SubGroup subGroup; 
}

Imagine I have an entity PriceTable and sometimes I need to have values to all types of coffee and sometimes by some specific types. For coffee A1, its id would be "ca1", for coffee A2 its id would be "ca2" and for generic coffee could be "cag" and subGroup attribute would be null.

Someone finds another way to transform these use cases into entities? I thought about a Strategy pattern but could not get the code to this

2
  • What do you mean by "need to have values to all types of coffee", and why you think it should be a responsibility of an entity rather than a repository? There are quite few ways to express a "group of entities", depending on usage. I'd like to see more concrete examples. Jun 18, 2021 at 1:06
  • I mean that in some uses cases I need to make a reference to all types of coffee and I would try not to store a list os ids at database. Jun 18, 2021 at 3:03

2 Answers 2

1

In general, how you organize your data very much depends on the data itself. It is so contextual that you can't really give any generalized advice that applies universally.

To keep things simple, let's invent a data set:

  • A - Instant coffee
  • B - Black bean coffee
    • B1 - Freshly ground black bean coffee
    • B2 - Roasted black bean coffee
  • C - Red bean coffee
    • C1 - Freshly ground red bean coffee
      • C11 - Brand ABC
      • C12 - Brand DEF

Since you want to interchangeably reference either a coffee group or subtype, it makes sense to model this data as a single recursive set. That is to say, one table contains everything, and some of its entries refer to other entries of the same table.

Focusing solely on the PK and parent FK, the table would contain something like:

PK Parent FK
A NULL
B NULL
B1 B
B2 B
C NULL
C1 C
C11 C1
C12 C1

Keep in mind that this is an oversimplification. In reality, you'd be much better off using a database-generated ID (i.e. int or guid) for PK/FK. I just used the string codes here to make it easier to understand which entry refers to which.

Also, I omitted other columns such as the name of the coffee type or any other data you might want to store here. Of course, you can add these as you see fit.

On a code level, you can establish the same entity, i.e. something along the lines of:

public class CoffeeType
{
    public string Code { get; set; }
    public string ParentCode { get; set; }
}

Again, using string is an oversimplification here. int or Guid are much preferred database key types.

And now, every other operation in your domain can interchangeably refer to either a coffee supertype or subtype. For example:

public class CoffeeMenuItem
{
    public CoffeeType Type { get; set; }
    public double Price { get; set; }
}

var menu = new List<CoffeeMenuItem>()
{
    new CoffeeMenuItem()
    {
        Type = _repo.GetByCode("C"),    // Price for the entire C group
        Price = 4.50
    },
    new CoffeeMenuItem()
    {
        Type = _repo.GetByCode("B1"),   // Price for a specific subtype
        Price = 2.50
    },
    new CoffeeMenuItem()
    {
        Type = _repo.GetByCode("B2"),   // Price for a specific subtype
        Price = 2.75
    }
};
0

How about making the ProductGroup its own entity (backed by a header table and a N:M table)?

You could introduce a PricingRule entity that consists of a matching strategy (as you already mentioned):

class PricingRule {
  boolean matches( Product )
  Price getPrice()
  String getOfferName()
}

A price table would consist of an ordered list of PricingRules. The first match (or maybe lowest priced match?) wins. There could be rules like GroupPricingRule, SpecificCoffeePricingRule, DefaultPricePricingRule (last rule, pulls price from Product), SeasonDecoratorPricingRule etc. Make them nestable to gain the most of it (nesting should probably lead to a nestable MatchingStrategy value object within the PricingRule).

You could also manage the prices in a DMN table instead of creating your own rule system.

This way you can easily price all Products without keeping a list of all of them.

Depending on the domain you would probably need also a MenuTable entity that manages which products (Coffees) should be listed under which PrincingRule set. You could also use rules to determine which Products are presented on this table.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.