Each User can have several Subscriptions, and of course each Subscription can be subscribed by many Users (n:m).
When implementing this with Doctrine 2.0, I use a "join table" (e.g. users_subscriptions") which holds (user_id, subscription_id) and a "ManyToMany" mapping - The \Doctrine\ORM\Tools\Cli automatically creates the "users_subscriptions" DB table:
However if I'd like to add additional data for the junction between Users and Subscriptions, I need more fields in the "users_subscriptions" table (like subscription expiry, etc.).
How can I realize this with Doctrine 2.0?
I tried to introduce a new Entity that maps to the "users_subscriptions" table and holds "user_id", "subscription_id" and my additional fields. But this fails when Doctrine 2 complains about "No identifier/primary key specified" (Primary key is user_id AND subscription_id!)
> I tried to introduce a new Entity that maps to the > "users_subscriptions" > table and holds "user_id", "subscription_id" and my additional fields. > But this fails when Doctrine 2 complains about "No identifier/primary > key specified" (Primary key is user_id AND subscription_id!)
> Nico
You're already on the right way. As soon as the association table has additional fields you must map it into a full entity and turn the associations into one-many/one-one.
And, in such a case it is recommended best practice to give the association class its own id, just like a regular entity. And since it is discouraged to map foreign keys to object fields (because they have no meaning) just use a separate, incremental id.
Composite keys are in general possible (just specify @Id on the mapped fields that compose the PK) but not recommended as dealing with composite keys is more complicated for you and the ORM.
/** @Entity */ class UsersSubscriptions { /** @Id @GeneratedValue(strategy="AUTO") */ private $id; // map the following two as one-one private $user; private $subscription;
}
The only case where a composite key is fine and where doctrine indeed creates one is in a "real" many-many, where there is no association class.
Oh, and you should of course index the user_id and subscription_id,
since they're used for joining. Foreign keys might be indexed
automatically on some database platforms, I'm not sure.
You can do it with a unique constraint like this in annotations, I
think a unique constraint might be the best idea:
>> I tried to introduce a new Entity that maps to the
>> "users_subscriptions"
>> table and holds "user_id", "subscription_id" and my additional
>> fields.
>> But this fails when Doctrine 2 complains about "No identifier/primary
>> key specified" (Primary key is user_id AND subscription_id!)
>> Nico
> You're already on the right way. As soon as the association table
> has additional fields you must map it into a full entity and turn
> the associations into one-many/one-one.
> And, in such a case it is recommended best practice to give the
> association class its own id, just like a regular entity. And since
> it is discouraged to map foreign keys to object fields (because they
> have no meaning) just use a separate, incremental id.
> Composite keys are in general possible (just specify @Id on the
> mapped fields that compose the PK) but not recommended as dealing
> with composite keys is more complicated for you and the ORM.
> /** @Entity */
> class UsersSubscriptions {
> /** @Id @GeneratedValue(strategy="AUTO") */
> private $id;
> // map the following two as one-one
> private $user;
> private $subscription;
> }
> The only case where a composite key is fine and where doctrine
> indeed creates one is in a "real" many-many, where there is no
> association class.
I guess there is no way to build a composite primary key from a mapped
entity and another field? (Event if it's discouraged, I'd really like
to keep the current database model)
Something like this (each user can have several usernames, and in the
user_login table (userId, username) should be primary key:
> Oh, and you should of course index the user_id and subscription_id,
> since they're used for joining. Foreign keys might be indexed
> automatically on some database platforms, I'm not sure.
> You can do it with a unique constraint like this in annotations, I
> think a unique constraint might be the best idea:
> On Oct 29, 2009, at 6:20 PM, Roman Borschel wrote:
> > Hi,
> > On Oct 29, 2009, at 6:10 PM, Nico Kaiser wrote:
> > <snip>
> >> I tried to introduce a new Entity that maps to the
> >> "users_subscriptions"
> >> table and holds "user_id", "subscription_id" and my additional
> >> fields.
> >> But this fails when Doctrine 2 complains about "No identifier/primary
> >> key specified" (Primary key is user_id AND subscription_id!)
> >> Nico
> > You're already on the right way. As soon as the association table
> > has additional fields you must map it into a full entity and turn
> > the associations into one-many/one-one.
> > And, in such a case it is recommended best practice to give the
> > association class its own id, just like a regular entity. And since
> > it is discouraged to map foreign keys to object fields (because they
> > have no meaning) just use a separate, incremental id.
> > Composite keys are in general possible (just specify @Id on the
> > mapped fields that compose the PK) but not recommended as dealing
> > with composite keys is more complicated for you and the ORM.
> > /** @Entity */
> > class UsersSubscriptions {
> > /** @Id @GeneratedValue(strategy="AUTO") */
> > private $id;
> > // map the following two as one-one
> > private $user;
> > private $subscription;
> > }
> > The only case where a composite key is fine and where doctrine
> > indeed creates one is in a "real" many-many, where there is no
> > association class.
I know it's complicated for the ORM (performace-wise) and not that
elegant. But I really do need to keep the database structure (which
uses composite keys) as in the example I gave. I cannot add additional
fields, as we need to use the same database with old classes (not only
DDC)...
E.g. the "I18n" behavior of Doctrine 1.x generates DB tables with (id,
lang) as primary key. To simulate their behavior (and re-use the
existing DB tables without modifications!!), I need composite keys...
Nico
On 30 Okt., 12:05, Nico Kaiser <n...@kaiser.me> wrote:
> I guess there is no way to build a composite primary key from a mapped
> entity and another field? (Event if it's discouraged, I'd really like
> to keep the current database model)
> Something like this (each user can have several usernames, and in the
> user_login table (userId, username) should be primary key:
> On 29 Okt., 21:20, Roman Borschel <r.borsc...@gmx.net> wrote:
> > Oh, and you should of course index the user_id and subscription_id,
> > since they're used for joining. Foreign keys might be indexed
> > automatically on some database platforms, I'm not sure.
> > You can do it with a unique constraint like this in annotations, I
> > think a unique constraint might be the best idea:
> > On Oct 29, 2009, at 6:20 PM, Roman Borschel wrote:
> > > Hi,
> > > On Oct 29, 2009, at 6:10 PM, Nico Kaiser wrote:
> > > <snip>
> > >> I tried to introduce a new Entity that maps to the
> > >> "users_subscriptions"
> > >> table and holds "user_id", "subscription_id" and my additional
> > >> fields.
> > >> But this fails when Doctrine 2 complains about "No identifier/primary
> > >> key specified" (Primary key is user_id AND subscription_id!)
> > >> Nico
> > > You're already on the right way. As soon as the association table
> > > has additional fields you must map it into a full entity and turn
> > > the associations into one-many/one-one.
> > > And, in such a case it is recommended best practice to give the
> > > association class its own id, just like a regular entity. And since
> > > it is discouraged to map foreign keys to object fields (because they
> > > have no meaning) just use a separate, incremental id.
> > > Composite keys are in general possible (just specify @Id on the
> > > mapped fields that compose the PK) but not recommended as dealing
> > > with composite keys is more complicated for you and the ORM.
> > > /** @Entity */
> > > class UsersSubscriptions {
> > > /** @Id @GeneratedValue(strategy="AUTO") */
> > > private $id;
> > > // map the following two as one-one
> > > private $user;
> > > private $subscription;
> > > }
> > > The only case where a composite key is fine and where doctrine
> > > indeed creates one is in a "real" many-many, where there is no
> > > association class.
> I know it's complicated for the ORM (performace-wise) and not that
> elegant. But I really do need to keep the database structure (which
> uses composite keys) as in the example I gave. I cannot add additional
> fields, as we need to use the same database with old classes (not only
> DDC)...
> E.g. the "I18n" behavior of Doctrine 1.x generates DB tables with (id,
> lang) as primary key. To simulate their behavior (and re-use the
> existing DB tables without modifications!!), I need composite keys...
> Nico
> On 30 Okt., 12:05, Nico Kaiser <n...@kaiser.me> wrote:
>> Ok, thanks!
>> I guess there is no way to build a composite primary key from a
>> mapped
>> entity and another field? (Event if it's discouraged, I'd really like
>> to keep the current database model)
>> Something like this (each user can have several usernames, and in the
>> user_login table (userId, username) should be primary key:
>> On 29 Okt., 21:20, Roman Borschel <r.borsc...@gmx.net> wrote:
>>> Oh, and you should of course index the user_id and subscription_id,
>>> since they're used for joining. Foreign keys might be indexed
>>> automatically on some database platforms, I'm not sure.
>>> You can do it with a unique constraint like this in annotations, I
>>> think a unique constraint might be the best idea:
>>> On Oct 29, 2009, at 6:20 PM, Roman Borschel wrote:
>>>> Hi,
>>>> On Oct 29, 2009, at 6:10 PM, Nico Kaiser wrote:
>>>> <snip>
>>>>> I tried to introduce a new Entity that maps to the
>>>>> "users_subscriptions"
>>>>> table and holds "user_id", "subscription_id" and my additional
>>>>> fields.
>>>>> But this fails when Doctrine 2 complains about "No identifier/ >>>>> primary
>>>>> key specified" (Primary key is user_id AND subscription_id!)
>>>>> Nico
>>>> You're already on the right way. As soon as the association table
>>>> has additional fields you must map it into a full entity and turn
>>>> the associations into one-many/one-one.
>>>> And, in such a case it is recommended best practice to give the
>>>> association class its own id, just like a regular entity. And since
>>>> it is discouraged to map foreign keys to object fields (because
>>>> they
>>>> have no meaning) just use a separate, incremental id.
>>>> Composite keys are in general possible (just specify @Id on the
>>>> mapped fields that compose the PK) but not recommended as dealing
>>>> with composite keys is more complicated for you and the ORM.
>>>> /** @Entity */
>>>> class UsersSubscriptions {
>>>> /** @Id @GeneratedValue(strategy="AUTO") */
>>>> private $id;
>>>> // map the following two as one-one
>>>> private $user;
>>>> private $subscription;
>>>> }
>>>> The only case where a composite key is fine and where doctrine
>>>> indeed creates one is in a "real" many-many, where there is no
>>>> association class.
> // map the following two as one-one
> private $user;
> private $subscription;
> }
> I would just make sure that $userId and $subscriptionId is not
> revealed to the public, if possible.
> So whenever you need a composite PK that is contains a FK I guess you
> have no other choice than to map the FK to an entity field.
> Will let you know if I have a better idea.
> On Nov 2, 2009, at 4:02 PM, Nico Kaiser wrote:
> > I know it's complicated for the ORM (performace-wise) and not that
> > elegant. But I really do need to keep the database structure (which
> > uses composite keys) as in the example I gave. I cannot add additional
> > fields, as we need to use the same database with old classes (not only
> > DDC)...
> > E.g. the "I18n" behavior of Doctrine 1.x generates DB tables with (id,
> > lang) as primary key. To simulate their behavior (and re-use the
> > existing DB tables without modifications!!), I need composite keys...
> > Nico
> > On 30 Okt., 12:05, Nico Kaiser <n...@kaiser.me> wrote:
> >> Ok, thanks!
> >> I guess there is no way to build a composite primary key from a
> >> mapped
> >> entity and another field? (Event if it's discouraged, I'd really like
> >> to keep the current database model)
> >> Something like this (each user can have several usernames, and in the
> >> user_login table (userId, username) should be primary key:
> >> On 29 Okt., 21:20, Roman Borschel <r.borsc...@gmx.net> wrote:
> >>> Oh, and you should of course index the user_id and subscription_id,
> >>> since they're used for joining. Foreign keys might be indexed
> >>> automatically on some database platforms, I'm not sure.
> >>> You can do it with a unique constraint like this in annotations, I
> >>> think a unique constraint might be the best idea:
> >>> On Oct 29, 2009, at 6:20 PM, Roman Borschel wrote:
> >>>> Hi,
> >>>> On Oct 29, 2009, at 6:10 PM, Nico Kaiser wrote:
> >>>> <snip>
> >>>>> I tried to introduce a new Entity that maps to the
> >>>>> "users_subscriptions"
> >>>>> table and holds "user_id", "subscription_id" and my additional
> >>>>> fields.
> >>>>> But this fails when Doctrine 2 complains about "No identifier/
> >>>>> primary
> >>>>> key specified" (Primary key is user_id AND subscription_id!)
> >>>>> Nico
> >>>> You're already on the right way. As soon as the association table
> >>>> has additional fields you must map it into a full entity and turn
> >>>> the associations into one-many/one-one.
> >>>> And, in such a case it is recommended best practice to give the
> >>>> association class its own id, just like a regular entity. And since
> >>>> it is discouraged to map foreign keys to object fields (because
> >>>> they
> >>>> have no meaning) just use a separate, incremental id.
> >>>> Composite keys are in general possible (just specify @Id on the
> >>>> mapped fields that compose the PK) but not recommended as dealing
> >>>> with composite keys is more complicated for you and the ORM.
> >>>> /** @Entity */
> >>>> class UsersSubscriptions {
> >>>> /** @Id @GeneratedValue(strategy="AUTO") */
> >>>> private $id;
> >>>> // map the following two as one-one
> >>>> private $user;
> >>>> private $subscription;
> >>>> }
> >>>> The only case where a composite key is fine and where doctrine
> >>>> indeed creates one is in a "real" many-many, where there is no
> >>>> association class.
> > // map the following two as one-one
> > private $user;
> > private $subscription;
> > }
> > I would just make sure that $userId and $subscriptionId is not
> > revealed to the public, if possible.
> > So whenever you need a composite PK that is contains a FK I guess you
> > have no other choice than to map the FK to an entity field.
> > Will let you know if I have a better idea.
> > On Nov 2, 2009, at 4:02 PM, Nico Kaiser wrote:
> > > I know it's complicated for the ORM (performace-wise) and not that
> > > elegant. But I really do need to keep the database structure (which
> > > uses composite keys) as in the example I gave. I cannot add additional
> > > fields, as we need to use the same database with old classes (not only
> > > DDC)...
> > > E.g. the "I18n" behavior of Doctrine 1.x generates DB tables with (id,
> > > lang) as primary key. To simulate their behavior (and re-use the
> > > existing DB tables without modifications!!), I need composite keys...
> > > Nico
> > > On 30 Okt., 12:05, Nico Kaiser <n...@kaiser.me> wrote:
> > >> Ok, thanks!
> > >> I guess there is no way to build a composite primary key from a
> > >> mapped
> > >> entity and another field? (Event if it's discouraged, I'd really like
> > >> to keep the current database model)
> > >> Something like this (each user can have several usernames, and in the
> > >> user_login table (userId, username) should be primary key:
> > >> On 29 Okt., 21:20, Roman Borschel <r.borsc...@gmx.net> wrote:
> > >>> Oh, and you should of course index the user_id and subscription_id,
> > >>> since they're used for joining. Foreign keys might be indexed
> > >>> automatically on some database platforms, I'm not sure.
> > >>> You can do it with a unique constraint like this in annotations, I
> > >>> think a unique constraint might be the best idea:
> > >>> On Oct 29, 2009, at 6:20 PM, Roman Borschel wrote:
> > >>>> Hi,
> > >>>> On Oct 29, 2009, at 6:10 PM, Nico Kaiser wrote:
> > >>>> <snip>
> > >>>>> I tried to introduce a new Entity that maps to the
> > >>>>> "users_subscriptions"
> > >>>>> table and holds "user_id", "subscription_id" and my additional
> > >>>>> fields.
> > >>>>> But this fails when Doctrine 2 complains about "No identifier/
> > >>>>> primary
> > >>>>> key specified" (Primary key is user_id AND subscription_id!)
> > >>>>> Nico
> > >>>> You're already on the right way. As soon as the association table
> > >>>> has additional fields you must map it into a full entity and turn
> > >>>> the associations into one-many/one-one.
> > >>>> And, in such a case it is recommended best practice to give the
> > >>>> association class its own id, just like a regular entity. And since
> > >>>> it is discouraged to map foreign keys to object fields (because
> > >>>> they
> > >>>> have no meaning) just use a separate, incremental id.
> > >>>> Composite keys are in general possible (just specify @Id on the
> > >>>> mapped fields that compose the PK) but not recommended as dealing
> > >>>> with composite keys is more complicated for you and the ORM.
> > >>>> /** @Entity */
> > >>>> class UsersSubscriptions {
> > >>>> /** @Id @GeneratedValue(strategy="AUTO") */
> > >>>> private $id;
> > >>>> // map the following two as one-one
> > >>>> private $user;
> > >>>> private $subscription;
> > >>>> }
> > >>>> The only case where a composite key is fine and where doctrine
> > >>>> indeed creates one is in a "real" many-many, where there is no
> > >>>> association class.