0

You have Job *--1 Board, so in your database you will have a board_id in your jobs table.

Now, in the domain, Job can live without Board. So thinking about adding a boardId property to it doesn't seam logical to me.

Is it ok to manage it through the BoardRepository? for example calling to BoardRepository.addJob(Board board, Job job)? so the repository will map the Job to a database object and then add the board_id field when insert it?

The problem is... What if I want to query the Job through /jobs/{id}, I will need to have the boardId attribute in the domain class, so it will not be mapped to the right DTO.

Hope I'm being clear.

k-ter
  • 737
  • 1
  • 5
  • 15

1 Answers1

2

normally you have one aggregate per repository. So Repository.addJob(Board board, Job job) seems not a good choice. I don't know your problem domain .. but when we have Board as an aggregate or Root Entity of an Aggregate then Board is responsible for managing its jobs. So it keeps a list of its jobs, where Job is probably another entity. In general an aggregate is a cluster of connected domain objects and acts like a Facade for manipulating its state and the state of its entities and value objects. By applying these principles you would end with maybe something like this:

Board.addJob(Job job)    
BoardRepository.add(Board board)

If you queries are getting too complex and don't fit with your DDD model, then it's completly ok to logically seperate the write and the read model by simply adding an additional QueryService which maps simple dtos to your database. Hope i could help a bit :)

Repositories are your abstraction to your persistence strategy. So you would have one interface for your repository in your domain layer:

interface BoardRepository {
    add(Board board);
    update(Board board);
    delete(BoardId id);
    get(BoardId id);
}

If you would use a SQL Persistence Strategy, then you would implement this interface in e.g. your infrastructure layer like this.

class SqlBoardRepository implements BoardRepository {
    ...
}

So yes Repositories are responsible for persisting aggregates. You'll have one repository per Aggregate! Not one Repository for every Entity!

Primary Keys and foreign keys are a database related topic and normally you don't care about them in your domain models. Entities in you domain model are identified by business keys (which also can be used as primary key). For example an isbn identifies a book world wide and would be the business key of a Book entity and could also be used as a primary key in the database. Sometimes when using business key is too complex in your persistence model then you could use an additional surrogate key in your entities, which identifies your entity primarly on the persistence layer. You model your relationships between your domain objects with your business or surrogate keys in the db and a sql repository is responsible for mapping your domain models to database and vice versa.

Maybe you should read a bit about it, then you'll understand better. The blue book from Eric Evans or Implementing Domain Driven Design from Vaughn Vernon is a good start :)

brckner
  • 56
  • 5
  • Thanks for the answer. In your example, when you add a job to a board and it gets persisted, how do you persist it?? Is the repository responsible of saving the job to its table with the foreign key `board_id` ? When I get a Job from its own repository, the repository wont pay attention to the `board_id`, but when I add the job to a board, it will update the `board_id` field? That's the question. – k-ter Jul 21 '20 at 22:33
  • I've edited my answer... maybe it gets a bit clearer – brckner Jul 22 '20 at 07:50
  • Thanks again, I appreciate. I don't like the last comment, I've read a lot before asking a question, and these are my little doubts about it. I know everything you mentioned, but maybe I am not being clear. If I call `Board.addJob(Job job)`, it means that I have an internal array of Jobs loaded into Board to satisfice the Board integrity, right?. What if there is thousands of jobs in it? Do I have to query all of them through `BoardRepository.get(id)` just to call `Board.addJob(job)` and then save the board? – k-ter Jul 22 '20 at 13:50
  • I don't know your business domain you're trying to implement, but loading thousands of entities within an aggregate is not a good idea. So in your case is a board simply a Repository for jobs? Or is it an aggregate? So in case a board is an aggregate and job is an aggregate too, then these two aggreagtes are only connected by its business keys. so a job might have something like a BoardId as an attribute, which represents the reference to a Board... in your jobrepository you could implement something like this to get all jobs for a specific board. JobRepository.allJobsFor(BoardId boardId) – brckner Jul 22 '20 at 14:13
  • 1
    That’s exactly what I was talking about. Yes! They are aggregates. What smells for me is that I have that “business key” in Job for a Board, so... the Job is coupled to Board, while a Job should know nothing about boards. Having a boardId attribute means that Job is aware of Board. Is it right? – k-ter Jul 22 '20 at 15:04
  • I think there's nothing wrong, so at least one needs to know about each other, right? so if you store a boardId in your job referencing to the board aggregate, there should be no problem with it. If it fits, you could use a factory method in your board aggregate which creates and initializes a job with the boardId (you could argue that a board might be reponsible for creating new jobs). Afterwards persisting the job in the jobrepository. You can then query jobs with the jobrepository e.g. jobrepository.allJobsForBoard(BoardId id) or query it with sql directly and map it to dtos. – brckner Jul 22 '20 at 15:58