Skip to content

Fetching lazy loaded component causes n + 1 query when querying a subclass abstraction #3289

@nfplee

Description

@nfplee

I've found that when doing a LINQ query and fetching a component it seems to work fine when querying a class, but if I try to query the interface the class implements then the fetch doesn't appear to work.

For example say I have the following:

public class Entity : IEntity
{
    public virtual int Id { get; set; 
    public virtual string Name { get; set; }
    public virtual Component Component { get; set; }
}

public class SubEntity : Entity, ISubEntity
{
    public virtual bool SomeProperty { get; set; }
}

public class Component
{
    public virtual string Field { get; set; }
}

public interface IEntity
{
    int Id { get; set; }
    string Name { get; set; }
    Component Component { get; set; }
}

public interface ISubEntity : IEntity
{
    public bool SomeProperty { get; set; }
}

Which is mapped like so:

protected override HbmMapping GetMappings()
{
    var mapper = new ModelMapper();
    mapper.Class<Entity>(rc =>
    {
        rc.Id(x => x.Id, m => m.Generator(Generators.Identity));
        rc.Property(x => x.Name);
        rc.Component(x => x.Component);
    });
    mapper.JoinedSubclass<SubEntity>(rc =>
    {
        rc.EntityName(typeof(ISubEntity).FullName);
        rc.Key(k => k.Column("Id"));
        rc.Property(x => x.SomeProperty);
    });
    mapper.Component<Component>(rc =>
    {
        rc.Property(x => x.Field);
        rc.Lazy(true);
    });

    return mapper.CompileMappingForAllExplicitlyAddedEntities();
}

Now if I was to say the following, the database would be hit once:

var result = session.Query<SubEntity>()
    .Fetch(e => e.Component)
    .ToList();

// Make sure the component field is executed.
foreach (var entity in result)
{
    var foo = entity.Component?.Field;
}

However if I say the following, the database would be hit for each entity in the result:

var result = session.Query<ISubEntity>()
    .Fetch(e => e.Component)
    .ToList();

// Make sure the component field is executed.
foreach (var entity in result)
{
    var foo = entity.Component?.Field;
}

Edit: See below for a test case.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions