Ayende has a blog post detailing how to combat the "n+1" problem in nHibernate. In essence, the problem is this:
Assume you have two tables, "BlogPosts" and "Comments" with a one-to-many relationship between them (i.e. each BlogPost can have multiple Comments). Now, let's say you want to execute the following nested for loop:
foreach (BlogPost post in blogposts)
{
foreach (Comment comment in post.Comments)
{
// Do something
}
}
From what I understand, the classes that SubSonic generate are lazyload by default (I don't want to turn this off completely because it's useful in most circumstances, just not this one). That means that every time the inner loop is executed (i.e. when post.Comments is accessed), a separate query must be sent to the database to retrieve the comments.
So if you have 80 blog posts, that's 1 query to get the list of blog posts, then 80 queries to get the comments for each of them. If the comments were eager loaded, however, this would be reduced to 1 query.
Is there any way to combat this problem in SubSonic currently?
Unless you create a query to select from Comment based on post IDs, I don't think there's a way to combat it. This would get you down to two. One query to select the post IDs you want, then another to get all the comments for that list of post IDs.
I think what you should do is create a partial class method that will get all the comments. Not so clean but should work.
I too use partial classes and load related table classes like so:
Partial Public Class Book
Private _Author as Database.Author
Property Author() as Database.Author
Get
If _Author is nothing then
' Load the author class here.
End if
return _Author
End get
Set
'....
End Set
End Property
End Class
Related
I've created a Query Loop on a Post. It works fine. If I change to Code Editor, I see there is a queryId:{int} which is generated. I'm wondering where that int id is coming from each time I add a new Query Loop. I have looked in the db to no avail (yet).
Why I'm asking. I am duplicating a post with that same Query Loop. When duplicated, the queryId remains the same. And it seems to be okay that I change the filtering (as in it doesn't change the filtering on the original that I duplicated from). The config for the query itself is in the Post ... which again makes me wonder why it needs this id?
I have assigned a random {int} too to see if that would break things, but it didn't.
Any idea where that id is stored in the db?
The queryId attribute is used to differentiate multiple query loop blocks on the same page for pagination. When you go to the next page using a pagination block in the query loop block, the queryId is included in the URL query (?query-{id}-page=2) to tell wordpress which query loop block you want the next page of. The ID is generated when the block is created, and stored only in the block attributes (the comments you see in code view), not in the database.
https://github.com/WordPress/gutenberg/blob/wp/5.9/packages/block-library/src/query/edit/index.js#L79
So yes, it SHOULD be different for each query loop block on a page if you expect pagination to work for each of them independently.
I'm using Symfony4. I have a database structure with three tables, with two one-to-many relations relating them. For instance:
House -> Person -> Dog
Each house can contain many persons, each person can own many dogs. (My database isn't really about houses and dogs, the actual table names have been changed to protect the innocent.) Using Doctrine entities, I of course have functions like $house->getPersons() and $person->getDogs(). But what is the correct way to implement a function like $house->getDogs()? There are several solutions I can come up with, but none of them seem like a "good" solution to me:
I could simply add a one-to-many relation relating House to Dog. However, this goes against one of the fundamental rules of normal database structure: no redundant data. The relation house->person->dog is already expressed in the database, so adding another relation directly from house->dog is not only redundant, but could potentially lead to a situation where a dog's person lives in one house, but the dog lives in another (which is not something I want).
I could just do something like
foreach($house->getPersons() as $person){
$person->getDogs();
// Do something with each dog
...
}
This isn't well optimized, as I'd be running a separate query for each person - potentially a lot of queries - when I could easily be running one query with a couple joins.
I could use the HouseRepository or a query builder within the House entity to run a custom query. This, as I understand it, is frowned upon in Symfony. We generally don't want any DQL or use of repositories in the entity classes, correct?
I could use the HouseRepository from within services/controllers to run a custom query. This would be a simple way, but feels a little inelegant. Nevertheless, I have a feeling this might be the "right" way.
To sum up: I have a feeling I should be able to somehow put this fairly simple double-join in my entity, and not have to go to the repository level to get this data. To be clear, I'm not asking how to write a DQL join, I'm asking where the right place to put it is, or if there's some clever Symfony way to do this using Criteria or something similar.
If you want call $house->getDogs() you could add a method in your House entity.
public function getDogs()
{
/** #var Doctrine\Common\Collections\ArrayCollection */
$dogs = new ArrayCollection();
if ($persons = $this->getPersons()) {
foreach($persons as $person) {
if ($d = $person->getDogs()) {
$dogs->add($d);
}
}
}
return $dogs;
}
Iterating through each person in the way you've done it is perfectly valid. If you are looking to minimize the hits to the database, you can use some join statements to "pre select" everything you need all in one trip to the db. Using a technique like the one shown here, try the code below.
Assuming one to many relationship dog->persons and a second one to many relationship person->dogs, then in your HouseRepository use a method that pulls all relevant data in a single query, including all related Person(s) and Dog(s).
class HouseRepository extends ServiceEntityRepository
{
$qb = $this->createQueryBuilder('house')
->leftJoin('house.persons', 'persons')
->addSelect('persons')
->leftJoin('persons.dogs', 'dogs')
->addSelect('dogs')
->getQuery()->getResult();
}
This is untested of course, and I suspect the returned data structure will be so messy that even if it works your code might be ugly to handle it.
I'm displaying a paginated list of entities, and I currently have a normal "page" parameter in the route.
But I would also like to display the page containing a given entity (of which I would get the id in the route too). So I need to get the page number related to this entity.
I'm using KnpPaginatorBundle, but I guess there is no such functionality in it.
I've seen the answer with Hibernate here: is there such index() function in Doctrine 2 ?
Or any way to do this easily ?
Thanks!
So, just counted the number of entities before the current one, it appears that PagniatorBundle doesn't do such thing.
I am trying to create an index in raven that will (to all intents and purposes) project all comments on all blog-posts that were created by a specific user. At present I have managed a map statement, which only returns the posts that have comments.
from post in docs.Posts
from comment in Hierarchy(post, "Comments")
select new { comment.User, comment.Text }
At the end of this, I will want to page through the comments, so I need to get a flat list of all matching items.
Thanks
What is the problem that you have run to?
You are projecting the comment data out, you need to tell RavenDB to store the fields, but you can now query it just fine.
Just dipping my toes into Linq2sql project after years of rolling my own SQL Server DB access routines.
Before I spend too much time figuring out how to make linq2sql behave like my custom code used to, I want to check to make sure that it isn't already "built" in behavior that I can just use by setting up the relationships right in the designer...
Very simple example:
I have two tables: Person and Notes, with a 1 to many relationship (1 Person, many notes), linked by Person.ID->Note.PersonID.
I have a stored procedure (all data access is done via SP's and I plan on continuing that) which makes the Link2SQL a bit more work for me.
sp_PersonGet(#ID int) which returns the person record and sp_PersonNotesGet(#PersonID) which returns a set of related notes for this person.
So far so good, I have an object:
Dim myPerson As Person = db.PersonGet(pnID).Single
and I can access my fields: myPerson.Name, myPerson.Phone etc.
and I can also do a
Dim myNotes As Notes = db.PersonNotesGet(pnID)
to get a set of notes and I can iterate thru this list like:
For Each N As Note In myNotes
( do something)
Next
This all works fine...BUT....What I would prefer is that if I call:
myPerson = db.PersonGet(pnID)
that I also end up with a myPerson.Notes collection that I can iterate thru.
For Each N As Note In myPerson.Notes
( do something)
Next
Basically, Linq2SQl would need to call 2 stored procedures each time a Person record is created...
Is this doable "out of the box", or is this something I need to code around for myself?
This is normally what we would call child collections and they can be eager loaded or lazy loaded. Read these:
http://davidhayden.com/blog/dave/archive/2009/01/08/QuickExamplesLINQToSQLPerformanceTuningPerformanceProfilingORMapper.aspx
http://www.thinqlinq.com/default/Fetching-child-records-using-Stored-Procedures-with-LINQ-to-SQL.aspx
It uses partial classes. You can add your own "Notes" property to your Person class and initialize it in it's GETter function. This would be better than populating the notes every time you load a person record.
I believe that you can do this more or less out of the box, although I haven't tried it -- I don't use stored procedures with LINQ. What you would need to do is change the Insert/Delete/Update methods from using the runtime to use your stored procedures. Then you'd create an Association between your two entity tables which would create an EntitySet of Notes on the Person class and a EntityRef of Person on the Notes class. You can set this up to load automatically or using lazy loading.
The only tricky bit, as far as I can see, is the change from using the runtime generated methods to using your stored procedures. I believe that you have to add them into the data context as methods (by dropping it on your table from the server explorer in the designer) before it is available to use instead.