views:

409

answers:

2

My SQL table looks like this:

CREATE TABLE Page (
    Id int primary key,
    ParentId int, -- refers to Page.Id
    Title varchar(255),
    Content ntext
)

and maps to the following class in my ActiveRecord model:

[ActiveRecord]
public class Page {

    [PrimaryKey]
    public int Id { get; set; }

    [BelongsTo("Parent")]
    public virtual Page Parent { get; set; }

    [Property]
    public string Title { get; set; }

    [Property]
    public string Content { get; set; }

    [HasMany(typeof(Page), "Parent", "Page")]
    public IList<Page> Children { get; set; }
}

I'm using ActiveRecord to retrieve the tree roots using the following code:

var rootPages = new SimpleQuery<Page>(@"from Page p where p.Parent is null");
return(rootPages.Execute());

This gives me the correct object graph, but a SQL Profiler trace shows that child pages are being loaded by a separate query for every non-leaf node in the tree.

How can I get ActiveRecord to load the whole lot up front ("SELECT * FROM Page") and then sort the in-memory objects to give me the required parent-child relationships?

A: 

Try this:

var rootPages = new SimpleQuery<Page>(@"from Page p left join fetch p.Children where p.Parent is null");
return(rootPages.Execute());

This will cause the Children collection of each Page in the result set to be populated out during the initial query, which should reduce your overall query load to a single query.

DotNetGuy
This will only load the first level of children. Any tree with a depth greater than 2 will still exibit the N+1 issue.
oillio
True. But the questioner's example doesn't have a second level of children. You'd need to design the query to suit the specific circumstances on each occasion. AFAIK there's no one-size-fits all approach.
DotNetGuy
+2  A: 

The easiest way to do this is to fetch the entire table, then filter the result. This is pretty easy, if you are using linq.

var AllPages = ActiveRecordMediator<Page>.FindAll();
var rootPages = AllPages.Where(p => p.Parent == null);
oillio