Skip to content

Fetch Join generates incorrect SQL joins for the same entity type #2201

Closed
@PiotrKlecha

Description

@PiotrKlecha

Using a Fetch Join mapping for an entity that contains references to entities of the same type results in incorrect joins in SQL query.

For an entity:

public class Entity
{
	public virtual ulong? EntityId { get; set; }
	public virtual string EntityNumber { get; set; }
	public virtual Entity ReferencedEntity { get; set; }
	public virtual Entity AdditionalEntity { get; set; }
	public virtual Entity SourceEntity { get; set; }
}

and mapping:

mapper.Class<Entity>(m =>
{
	m.Id(c => c.EntityId, id =>
	{
		id.Generator(Generators.Native);
	});
	m.Property(c => c.EntityNumber);
	m.ManyToOne(c => c.ReferencedEntity, p =>
	{
		p.Column("ReferencedEntityId");
		p.Fetch(FetchKind.Join);
	});
	m.ManyToOne(c => c.AdditionalEntity, p =>
	{
		p.Column("AdditionalEntityId");
		p.Fetch(FetchKind.Join);
	});
	m.ManyToOne(c => c.SourceEntity, p =>
	{
		p.Column("SourceEntityId");
		p.Fetch(FetchKind.Join);
	});
});

running the following query:

session
	.QueryOver<Entity>()
	.Where(e => e.EntityId == 1)
	.List();

results in an incorrect SQL:

    SELECT
        this_.EntityId as entityid1_0_3_,
        this_.EntityNumber as entitynumber2_0_3_,
        this_.ReferencedEntityId as referencedentityid3_0_3_,
        this_.AdditionalEntityId as additionalentityid4_0_3_,
        this_.SourceEntityId as sourceentityid5_0_3_,
        entity2_.EntityId as entityid1_0_0_,
        entity2_.EntityNumber as entitynumber2_0_0_,
        entity2_.ReferencedEntityId as referencedentityid3_0_0_,
        entity2_.AdditionalEntityId as additionalentityid4_0_0_,
        entity2_.SourceEntityId as sourceentityid5_0_0_,
        entity3_.EntityId as entityid1_0_1_,
        entity3_.EntityNumber as entitynumber2_0_1_,
        entity3_.ReferencedEntityId as referencedentityid3_0_1_,
        entity3_.AdditionalEntityId as additionalentityid4_0_1_,
        entity3_.SourceEntityId as sourceentityid5_0_1_,
        entity4_.EntityId as entityid1_0_2_,
        entity4_.EntityNumber as entitynumber2_0_2_,
        entity4_.ReferencedEntityId as referencedentityid3_0_2_,
        entity4_.AdditionalEntityId as additionalentityid4_0_2_,
        entity4_.SourceEntityId as sourceentityid5_0_2_ 
    FROM
        Entity this_ 
    left outer join
        Entity entity2_ 
            on this_.ReferencedEntityId=entity2_.EntityId 
    left outer join
        Entity entity3_ 
            on entity2_.AdditionalEntityId=entity3_.EntityId 
    left outer join
        Entity entity4_ 
            on entity3_.SourceEntityId=entity4_.EntityId 
    WHERE
        this_.EntityId = :p0;

entity3_ is joined to entity2_ and entity4_ is joined to entity3_ while both should be joined to this_ like entity2_.

Explicitly fetching referenced entities:

session
	.QueryOver<Entity>()
	.Where(e => e.EntityId == 1)
	.Fetch(SelectMode.Fetch,
		e => e.ReferencedEntity,
		e => e.AdditionalEntity,
		e => e.SourceEntity)
	.List();

adds correct joins to SQL but previous still remain (entity3_ and entity4_):

    SELECT
        this_.EntityId as entityid1_0_5_,
        this_.EntityNumber as entitynumber2_0_5_,
        this_.ReferencedEntityId as referencedentityid3_0_5_,
        this_.AdditionalEntityId as additionalentityid4_0_5_,
        this_.SourceEntityId as sourceentityid5_0_5_,
        entity2_.EntityId as entityid1_0_0_,
        entity2_.EntityNumber as entitynumber2_0_0_,
        entity2_.ReferencedEntityId as referencedentityid3_0_0_,
        entity2_.AdditionalEntityId as additionalentityid4_0_0_,
        entity2_.SourceEntityId as sourceentityid5_0_0_,
        entity3_.EntityId as entityid1_0_1_,
        entity3_.EntityNumber as entitynumber2_0_1_,
        entity3_.ReferencedEntityId as referencedentityid3_0_1_,
        entity3_.AdditionalEntityId as additionalentityid4_0_1_,
        entity3_.SourceEntityId as sourceentityid5_0_1_,
        entity4_.EntityId as entityid1_0_2_,
        entity4_.EntityNumber as entitynumber2_0_2_,
        entity4_.ReferencedEntityId as referencedentityid3_0_2_,
        entity4_.AdditionalEntityId as additionalentityid4_0_2_,
        entity4_.SourceEntityId as sourceentityid5_0_2_,
        entity5_.EntityId as entityid1_0_3_,
        entity5_.EntityNumber as entitynumber2_0_3_,
        entity5_.ReferencedEntityId as referencedentityid3_0_3_,
        entity5_.AdditionalEntityId as additionalentityid4_0_3_,
        entity5_.SourceEntityId as sourceentityid5_0_3_,
        entity6_.EntityId as entityid1_0_4_,
        entity6_.EntityNumber as entitynumber2_0_4_,
        entity6_.ReferencedEntityId as referencedentityid3_0_4_,
        entity6_.AdditionalEntityId as additionalentityid4_0_4_,
        entity6_.SourceEntityId as sourceentityid5_0_4_ 
    FROM
        Entity this_ 
    left outer join
        Entity entity2_ 
            on this_.ReferencedEntityId=entity2_.EntityId 
    left outer join
        Entity entity3_ 
            on entity2_.AdditionalEntityId=entity3_.EntityId 
    left outer join
        Entity entity4_ 
            on entity3_.SourceEntityId=entity4_.EntityId 
    left outer join
        Entity entity5_ 
            on this_.AdditionalEntityId=entity5_.EntityId 
    left outer join
        Entity entity6_ 
            on this_.SourceEntityId=entity6_.EntityId 
    WHERE
        this_.EntityId = :p0;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions