Doctrine ORM Single Table Inheritance association problem (always Eager loading contrary to documentation)) - orm

I have an issue with single table inheritance and I'm not sure if I'm interpreting the documentation correctly.
First: I've not copied my code / entity mappings verbosely (or even using the correct syntax) here as I think the problem can be better communicated abstractly.
If this is not acceptable by all means say so and I'll add the full code - but it is LONG and I think my question can be answered without it.
If it helps I can draw
an ER diagram to try and communicate what I'm trying to do.
If you read the following and think 'hey that should work' - then tell me and I'll upload the real code
Second: I don't use lazy loading anywhere. Before accessing my entities I make sure that I load every related entity that I'm going to be accessing by writing DQL up front - so the following issue is fairly terminal to my application)
The Setup:
I have some entities - these make up the core of my application.
// #entity AnimalTrainingSchool
// oneToMany: trainingDepartment
fields: [name / location / year founded]
// #entity trainingDepartment
oneToMany: animalTrainer
oneToOne: building
fields: [capacity]
// #entity animalTrainer
fields: [name / age / qualification]
I access them frequently and in different contexts - but I commonly iterate though levels and access properties and relations for these entities.
foreach ($animalTrainingSchool as $school){
echo $school->getName() . ' at ' . $school->getLocation();
echo 'These are the training departments for this school:';
foreach ($school->getTrainingDepartments as $trainingDepartment){
echo $trainingDepartment->getAnimalTypeTrained() . ' are trained in this department';
}
}
I make sure that all of these are loaded up front by forming my DQL and executing it - to limit the number of SQL queries (to one).
This all works great (fairly standard stuff).
DQL Example : "SELECT ats, td, at FROM AnimalTrainingSchool ats JOIN AnimalTrainingSchool.trainingDepartments td JOIN td.animalTrainer at";
This sets up my collection and means that I can traverse it without having to issue additional queries
The Problem:
I have mapped other entites elsewhere in my application - very similarly to this (NOTE: My overall question is very similar to the below question with one MAJOR difference (see below)
Doctrine 2 Inheritance Mapping with Association
// NB: new awards are issued each time they are awarded - so it is meant to be a oneToOne relationships - the awards are unique
// #entity award
{id information / table information / discriminator map / inheritance type (SINGLE_TABLE)}
fields: [medalMaterial / award_serial_number]
//departmentAward extends award
oneToOne: trainingDepartment
//trainerAward extends award
oneToOne: animalTrainer
then I made the relationship bidirectional by modifying my initial entities
// #entity trainingDepartment
oneToMany: animalTrainer
oneToOne: building
oneToOne: departmentAward
fields: [capacity]
// #entity animalTrainer
fields: [name / age / qualification]
oneToOne: trainerAward
What Happens
Now when I access my original entities in exactly the same way as above - they automatically (eagerly) load the associated entity for their awards though I'm not telling them to.
This is especially bad when I'm iterating though a whole bunch of trainingDepartments / AnimalTrainers and Doctrine is executing an SQL statement for EVERY entity.
For 20 departments with 10 trainers in each - this is 200 additional queries.
//Given the exact same DQL and foreach loop as above (note that at no stage am I accessing awards) - I get a ton of extra queries that look like this
"SELECT award.property1, award.property2, award.property3 FROM awardTable LEFT JOIN trainingDepartmentTable ON award.awardee_id = trainingDepartmentTable.id and award.discriminatorColumn IN ('departmentAward')";
// or...
"SELECT award.property1, award.property2, award.property3 FROM awardTable LEFT JOIN animalTrainerTable ON award.awardee_id = animalTrainerTable.id and award.discriminatorColumn IN ('trainerAward')";
None of what is being generated is incorrect - it's just that having read the following question it seems to me like I have set this up as the documentation describes (and in the opposite way to #Matthieu; namely - that If I related my initial 3 entites to the LOWEST level entities
rather than the 'award' base class then they SHOULD be able to use proxies instead of attempting to eagerly load the entities.
Stackoverflow Question which is asking the opposite of what I am describing
Doctrine 2 Inheritance Mapping with Association
Relevant Doctrine Documentation
http://www.doctrine-project.org/docs/orm/2.0/en/reference/inheritance-mapping.html#performance-impact
There is a general performance
consideration with Single Table
Inheritance: If you use a STI entity
as a many-to-one or one-to-one entity
you should never use one of the
classes at the upper levels of the
inheritance hierachy as
“targetEntity”, only those that have
no subclasses. Otherwise Doctrine
CANNOT create proxy instances of this
entity and will ALWAYS load the entity
eagerly.
It seems to me that regardless of whether or not you are joining to the base level entity or a subclassed entity - Doctrine will eagerly load the associations and will not attempt to use proxies.
Again: I can post real code - but given the length of the question already I felt it was best not to. Any input greatly appreciated.

The inverse side of a oneToOne relationship can not be lazy loaded. In order to support lazy loading, Doctrine needs to create a proxy object, but proxy objects need to have an identifier associated with them. In the case of oneToOne relationships, the identifier is only available on the owning side. So the inverse relationship has to be loaded eagerly.
You should try to fetch join these associations if possible. Version 2.1 will automatically force fetch joins for inverse oneToOne relationships.

Related

Nhibernate Query with multiple one to many mappings

I'm a beginner in NHibernate. I have to write a complex query on say an "Employee" to populate all the associations for Employee based on the where clause. What I'm looking for is similar to this - when you do a Employee.FindById(10) should fill up OwnedDepartment, SubscribedGroups etc.
The Employee model I need to populate is really heavy (many associations with other objects)
but I need to populate only few associations. How do I achieve it using a query over? or any other approaches?
Updated
I was reading about eager loading just now, has it something to do with the loading ? In my map I have not mentioned any loading techniques, so by default all of my employee's child element are getting loaded already. There is a bunch of queries getting triggered underneath.
All the associations are lazy loaded by default. That means that the load is triggered when you access it - that's why so many queries are issued. If you want to eagerly load the data (which means either joining the tables or - rarely - doing additional select queries at once), you have to specify it in your mapping or query, depending how you fetch your data. The concept is generally called "eager fetching".
If you want to get a single Employee by ID, the standard way to do it is using session.Get<Employee>(10) - but that approach means that eager loads need to be specified in the mapping. For mapping by code it will be c.Lazy(CollectionLazy.NoLazy); for collections or c.Lazy(LazyRelation.NoProxy) for many-to-one - see here or here for details.
I prefer specifying that kind of things in the query - just where it is used, not globally for the whole entity, regardless who is fetching and what for. In LINQ provider you have FetchMany(x => x.SubscribedGroups) for collections and Fetch(x => x.OwnedDepartment) for many-to-one relations. You can find similiar options in QueryOver, if that's your choice.

How do you map a HasOne relationship with nHibernate Fluent mapping and avoid N+1?

I have 2 tables ATable and AATable where both have a shared Primary Key - ATable.aKey and AATable.aKey to represent a one-to-one relationship. For my Fluent mapping I have a HasOne Relationship defined within my Fluent ATableMapping, all of which works fine. However I have noticed that querying for ATable generates a 2nd query (N+1) for the child Table AATable. My understanding is that Hasone eager loads by default, and I had assumed this would be part of the query for ATable, but I may well have this wrong?
I have researched various solutions including using .Not.LazyLoad().Fetch.Join(), PropertyRef, ForeignKey but I cannot seem to resolve the n+1 so that either it is Eager loaded with 1 query, or Lazy loaded and I can fetch the child with my queries.
Has anyone had any issues with this or have an example they know to work with no n+1? Grateful for any advice.
You have two options:
Not.LazyLoad() which disables possibility to provide lazy loaded related entity and it would enforce NHB to provide corresponding subselect within original query
Use component mapping so both entities point to the same table. This is better approach as once you decided to fetch both entities together, generated queries hit only one table - not two like within first option. This is definitely better for performance.

iOS CoreData - Rebuild relationships

I'm wondering if it's possible to "rebuild" relationships in Core Data.
Basically, I messed up when creating my entities, getting data from a SQL server i filled my entities as tables (one table by one table) and it seems now that the relationships are not working.
Let's take an example :
I've set up my model with my two entities (department and employee), with a relation one-to-many "myRelationWithDepartment" (one department many employees), and generated the managed object subclasses accordingly.
I got table department and table employees from my SQL server and inserted all employees in my entity employee and only then (because i have to retrieve first employees) all departments in my entity department, using Core Data, saving context, etc. Everything is fine, just the relationship is not working.
Now I'm able to make a fetch request upon a department or an employee, it works fine. But if I retrieve an employee and do this :
[[anEmployee myRelationWithDepartment] departmentName];
it's returning nil, no compilation warnings or errors, it just seems that no department is linked to an employee.
So I assume that the relations are not working.
I've included in the model the "id"s I had in my SQL tables, so I'm able to link them manually (but i have multiple entities actually).
I've gone through the Core-Data guide and found this :
[aDepartment.employees addObject:newEmployee]; // do not do this!
then KVO change notifications are not emitted and the inverse relationship is not updated correctly.
Recall that the dot simply invokes the accessor method, so for the same reasons:
[[aDepartment employees] addObject:newEmployee]; // do not do this, either!
That's why I assume relationships are badly shaped. Is there a way to rebuild the relationships afterwards (since i share some id's in the model between entities)?
I dig up more in Apple's documentation and relationship has to be filled manually :
To create the relationship "link" :
anEmployee.myRelationWithDepartment = departmentObject;
Alternatively, you can use:
[department addEmployeeObject:anEmployee];
Then when fetching objects you can access properties of related entities.
The problem is that Core-Data is "sold" as everything is doing quite by itself and in reality it's much deeper as it seems at first glance.

Is it possible to establish an association in Doctrine2 without target entity at hand?

There is a ManyToOne association defined between entities Pattern and Category (Pattern is an owning side of the relation). Category has many patterns, pattern belongs to one category. So there is a field Pattern.category with #ManyToOne Doctrine annotation.
Now, in my scenario I have the id of the Category entity (posted from form) that I want assign to Pattern.category field of the newly created Pattern (which will be persisted), but I don't want to load this Category entity - I don't need it, I just want to create a Pattern entity, assign it to a Category (which id I have), and persist it. It seems strange to me, that I have to load the Category entity just to establish the connection, when all I really need is just an id, which I already have.
Maybe it smells like using relational database concepts with ORM, but it seems completely pointless to load this entity just to establish connection, when I know id of that target entity.
I am new to Doctrine btw.
You can use Reference Proxy:
$category = $em->getReference('Category', $id);
$pattern->setCategory($category);

Many to Many relationship for single entity

I'm currently writing my first project using core data, and am having trouble working out how to query the relationship between some of my data.
In sql language, i have a Country table, which joins to a CountryLink M-M table containing the following fields:
countryId1
countryId2
bearing
What would be the correct way to model this in Core Data?
So far i have set up a single Country entity and a CountryLink entity (containing only a bearing field) and have added two 1-to-Many relationships from Country to CountryLink ('CountryLink1' and 'CountryLink2').
I've run the project and looked at the Sqlite db structure produced by Core Data (found here, using this sqlite gui), and the M-M join table seems correct (it contains the bearing, CountryLink1 and CountryLink2 fields), but i'm not sure how i would go about carrying out a fetch request for a single Country NSManagedObject to return an array of related Countries and their bearings?
Any help or related links would be much appreciated.
Thanks, Ted
First a word of warning:
Core Data is not SQL. Entities are not tables. Objects are not rows. Columns are not attributes. Core Data is an object graph management system that may or may not persist the object graph and may or may not use SQL far behind the scenes to do so. Trying to think of Core Data in SQL terms will cause you to completely misunderstand Core Data and result in much grief and wasted time.
See the Tequilla advice
Now, forgetting SQL and thinking in object graphs, your entities would look something like this:
Country{
someAttribute:string // or whatever
countryLinks<-->>CountryLink.country
}
CountryLink{
countryID1:string // or whatever
countryID2:string // or whatever
country<<-->Country.countryLinks
}
As you add Country and CountryLink objects you add them to the relationships as needed. Then to find CountryLink objects related to a specific Country object, you would perform a fetch on the Country entity for Country objects matching some criteria. Once you have that object, you simply ask it for the CountryLink objects in its countryLinks relationship. And your done.
The important thing to remember here is that entities in combination with managedObjects are intended to model real-world objects, conditions or events and the relationship between the same. e.g. a person and his cars. SQL doesn't really model or simulate, it just stores.