Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Violation of Doctrine Rule about foreign keys #16

Closed
maks-rafalko opened this issue Sep 14, 2016 · 8 comments
Closed

Violation of Doctrine Rule about foreign keys #16

maks-rafalko opened this issue Sep 14, 2016 · 8 comments

Comments

@maks-rafalko
Copy link

maks-rafalko commented Sep 14, 2016

Hi,

you are mapping foreign keys to object properties which is forbidden from Doctrine point of view.

Foreign keys have no meaning whatsoever in an object model. Foreign keys are how a relational database establishes relationships. Your object model establishes relationships through object references. Thus mapping foreign keys to object fields heavily leaks details of the relational model into the object model, something you really should not do.

Could you comment it? How to deal with it without violation this rule?

Why do you need userId inside Wish entity if you have one-to-many through join table?

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/best-practices.html#don-t-map-foreign-keys-to-fields-in-an-entity

@josecelano
Copy link

@borNfreee I think It could be because the sample uses two approaches:

1.- User is the aggregate root for Wishes.
2.- Wishes have a different life cycle than User (not aggregated version).

In the second case you need that UserId to kmow who is the User who has that wish.

But why do not we store the complete User reference inside the Wish instead of only the UserId?

If something I do not know. I asked something similar some time ago in the DDDinPHP google group:

https://groups.google.com/forum/#!searchin/dddinphp/jose$20celano%7Csort:relevance/dddinphp/KRH7WK-PjOA/mIrDcXjlAgAJ

and @carlosbuenosvinos replied me this:

If two entities (CoAuthor and Post) do not conform an Aggregate, you should:

1.- Reference each other using their ids (PostId, CoAuthorId)
2.- Create a repository for each entity and pass it to your Application Service (this is the recommended way in the DDD community, check the Vernon's videos talking about Aggregate Design with feedback from Greg Young and Eric Evans)
3.- Add to those repositories findersBy the other EntityId.

@Ocramius
Copy link

There's no rule like that in the ORM: it's a choice.

@maks-rafalko
Copy link
Author

@Ocramius If we are mapping foreign key to the object property, should we also define a relation?
If no, how to let Doctrine know that this property is a foreign key (constraint in DB)

@Ocramius
Copy link

If no, how to let Doctrine know that this property is a foreign key

Does it need to be a FK? Is eventual consistency acceptable?

@maks-rafalko
Copy link
Author

@Ocramius What do you mean by Eventual Consistency here?

  1. delay between some updates in DB
  2. or absence of FKs?

This question above is not related to ES/CQRS btw.

Let's have a simple example. User is a separate Aggregate (root), Wish is an Aggregate (root).
According to Vaughn Vernon's talks, we can only have a UserId inside Wish aggregate and we can't have object reference.

Doing all this stuff in Doctrine, I don't understand how to achieve this - how to have UserId but not User object inside Wish and at the same time have user_id as a FK in wishes table.
For this example let's say that this is a requirement to have user_id as a FK to avoid inconsistent state.

So the question is simple: does Doctrine support a mapped object property to be a FK?

From what I have read in SO, Hibernate does support it.

@Ocramius
Copy link

Ocramius commented Sep 28, 2016

or absence of FKs?

This. This is usually acceptable when building references throughout BCs or separate aggregates.

Doing all this stuff in Doctrine, I don't understand how to achieve this

You just map the field as an integer, or as a UserId embeddable, or as a UserId custom type, then define the FK at DB-level only.

For this example let's say that this is a requirement to have user_id as a FK to avoid inconsistent state.

That's exactly what is usually denied when referencing across aggregates. It should be treated as a separate, different-address-space DB.

@keyvanakbary
Copy link
Member

Really cool discussion here guys, thanks a lot for your contributions.

I think @Ocramius has answered pretty well your question. The Domain Model shouldn't be aware of the mechanics of the underlying persistence mechanism, it does not matter if is Doctrine or raw SQL. The UserId defines the identity of the User related to a specific Wish at the Domain level, it has nothing to do with the persistence mechanism. You might persist it over an In-Memory DB, Mongo or even a file where you don't have the concept of a Foreign Key. You need that so your SQL queries are optimal. Remember that he Domain does not care about low-level implementation details.

At the Infrastructure level, you can map the UserId Value Object to a SQL Foreign Key easily with Doctrine custom types. Check out this example.

I hope we've shed some light on the subject. Closing the issue now :)

@maks-rafalko
Copy link
Author

Thank you all for descriptive and useful inputs!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants