0
votes

The devil is in the details. I am looking into implementing event sourcing on existing catering application. I have an invoice which can be associated to a company,dept in company or employee in company.

Setup

Use case:

  • The company is sponsoring an event and has paid for the food.
  • There are clients coming in to visit a company dept and they have ordered food.
  • There is cafeteria and employee orders food. The company pays us but still needs to bill employee.

Domain Model

Invoice
  -> invoice Id
  -> Status
  -> CompanyId 
  -> DeptId  
  -> EmployeeId 
  -> Balance
  • Only companyId populated (bill company)
  • companyId + deptId (bill dept)
  • companyUd + deptId + employeeId (bill person)

Relation Table

| p_key | invoice_id | Reltn_Table | Reltn_id |
|-------|------------|-------------|----------|
| 1     | 12345      | Company     | 245242   |
| 2     | 67890      | Company     | 1241243  |
| 3     | 79166      | Dept        | 534214   |
| 4     | 792131     | Dept        | 412213   |
| 5     | 489965     | Employee    | 412323   |

Assume that the dept and employee table are somehow related to the company table.

I have another Event Source Table with Domain Model as INVOICE.

Event Store Table.

| event_id | invoice_id | Event            | Payload |
|----------|------------|------------------|---------|
| 1        | 12345      | Invoice_InReview | JSON    |
| 2        | 12345      | Invoice_Billed   | JSON    |
| 3        | 12345      | Invoice_Paid     | JSON    |
| 4        | 12345      | Invoice_Reversed | JSON    |
| 5        | 12345      | Invoice_Paid     | JSON    |

The rest service sometimes passes in either the employee,dept or employee id to apply updates to invoice.

QUESTION

I wanted to see if there is a way for event store to handle scenario where it does not need to query the relation table to retrieve the invoice/invoices and then apply events to it.

I was initially leaning towards having snapshot of domain model but the problem still remains since the dept or companyId is in JSON I cannot run retrieve events based on that.

No matter what way I see I will have make a call to retrieve invoice/invoices before I can apply event or do anything .Is there anything I am missing that will help me get rid of the Relational Table or that is a dream of the fools?

Also a side question

SNAPSHOTS are saved in same table as the event store correct ? The event type is SNAPSHOT right ? Please correct me if I am wrong on that

2

2 Answers

0
votes

I wanted to see if there is a way for event store to handle scenario where it does not need to query the relation table to retrieve the invoice/invoices and then apply events to it.

The Event store should not query any other table except its own. And also, it should not be the responsibility of the Event store to load an Aggregate and to apply the events to it (to rehydrate an Aggregate). This would be the responsibility of a Repository that uses an Event store.

The Event store is at a lower level, and it should have these two methods:

interface EventStore
{
    EventStream loadEvents(aggregateId);
    void appendEvents(aggregateId, previousEventStream, eventsToBeAppended);
}

It may have other methods, but at the same level of abstraction like the above.

On the other side, an Event sourcing aware Invoice repository would have this interface:

interface InvoiceRepository {
   Invoice loadInvoice(invoiceId);
   void persistInvoice(invoiceId, invoiceNewEvents);
}

Here is an example of such a (althought generic) repository.

0
votes

My arch. for the above probem would be like:

Invoice Agg status paid InvoiceInfo

InvoiceInfo CompanyInvoiceInfo DebtInvoiceInfo EmployeeInvoiceInfo

InvoiceCreated InvoiceInReview InvoiceBilled

will be the event review

Basically all api on agg. should require invoice_id to take the process further:

How user will get it and call API?

  1. While the invoice is generated and receipt given to user or on Mail where invoice id is written?
  2. List all invoices of an Employee , or Company or Dept ? I need a table(EmployeeInvoice) which have (EmployeeId and InvoiceId and InvoiceStatus) , a table (CompanyInvoice) which have (CompanyId, InvoiceId , InvoiceStatus) and DeptInvoice(DeptId, CompanyId , InvoiceStatus)

From this one can click the Api for InvoiceUpdate , here also InvoiceId is present.

  1. The case where one needs to Expose an API to outside world like /updateInvoice?employeeId= or /updateInvoice?companyId= or /updateInvoice?deptId= here one already knows from the API structure which kind of table one needs to query.

Now to answer your question:

  1. You will need some table to query back the invoice id in case in API InvoiceId is not mandated. That table can be flattened like i have done above or can be like you have there. As in Aggregate or EventStore model eventstore is based on a single ID always and API many times require to query it from diff. business ids.