Skip to content

Commit 838d17f

Browse files
committed
Fix join on interface
1 parent 96a9af7 commit 838d17f

File tree

4 files changed

+48
-7
lines changed

4 files changed

+48
-7
lines changed

src/NHibernate.Test/Async/Linq/ByMethod/JoinTests.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,5 +156,14 @@ public async Task CanInnerJoinOnSubclassWithBaseTableReferenceInOnClauseAsync()
156156
join o2 in db.Mammals on o.BodyWeight equals o2.BodyWeight
157157
select new { o, o2 }).Take(1).ToListAsync());
158158
}
159+
160+
[Test(Description = "GH-2805")]
161+
public async Task CanJoinOnInterfaceAsync()
162+
{
163+
var result = await (db.IUsers.Join(db.IUsers,
164+
u => u.Id,
165+
iu => iu.Id,
166+
(u, iu) => iu.Name).Take(1).ToListAsync());
167+
}
159168
}
160169
}

src/NHibernate.Test/Linq/ByMethod/JoinTests.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,14 @@ public void CanInnerJoinOnSubclassWithBaseTableReferenceInOnClause()
145145
join o2 in db.Mammals on o.BodyWeight equals o2.BodyWeight
146146
select new { o, o2 }).Take(1).ToList();
147147
}
148+
149+
[Test(Description = "GH-2805")]
150+
public void CanJoinOnInterface()
151+
{
152+
var result = db.IUsers.Join(db.IUsers,
153+
u => u.Id,
154+
iu => iu.Id,
155+
(u, iu) => iu.Name).Take(1).ToList();
156+
}
148157
}
149158
}

src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -792,17 +792,39 @@ private EntityJoinFromElement CreateEntityJoin(
792792

793793
private IQueryable ResolveEntityJoinReferencedPersister(IASTNode path)
794794
{
795+
string entityName = GetEntityJoinCandidateEntityName(path);
796+
797+
var persister = SessionFactoryHelper.FindQueryableUsingImports(entityName);
798+
if (persister == null && entityName != null)
799+
{
800+
var implementors = SessionFactoryHelper.Factory.GetImplementors(entityName);
801+
//Possible case - join on interface
802+
if (implementors.Length == 1)
803+
persister = SessionFactoryHelper.FindQueryableUsingImports(implementors[0]);
804+
}
805+
806+
if (persister != null)
807+
return persister;
808+
795809
if (path.Type == IDENT)
796810
{
797-
var pathIdentNode = (IdentNode) path;
798811
// Since IDENT node is not expected for implicit join path, we can throw on not found persister
799-
return (IQueryable) SessionFactoryHelper.RequireClassPersister(pathIdentNode.Path);
812+
throw new QuerySyntaxException(entityName + " is not mapped");
800813
}
801-
else if (path.Type == DOT)
814+
815+
return null;
816+
}
817+
818+
private static string GetEntityJoinCandidateEntityName(IASTNode path)
819+
{
820+
switch (path.Type)
802821
{
803-
var pathText = ASTUtil.GetPathText(path);
804-
return SessionFactoryHelper.FindQueryableUsingImports(pathText);
822+
case IDENT:
823+
return ((IdentNode) path).Path;
824+
case DOT:
825+
return ASTUtil.GetPathText(path);
805826
}
827+
806828
return null;
807829
}
808830

src/NHibernate/Linq/Visitors/QueryModelVisitor.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,9 @@ public bool ContainsBaseMember(JoinClause joinClause)
570570
{
571571
// Visit the join inner key only for entities that have subclasses
572572
if (joinClause.InnerSequence is ConstantExpression constantNode &&
573-
constantNode.Value is IEntityNameProvider entityNameProvider &&
574-
!_sessionFactory.GetEntityPersister(entityNameProvider.EntityName).EntityMetamodel.HasSubclasses)
573+
constantNode.Value is IEntityNameProvider &&
574+
ExpressionsHelper.TryGetMappedType(_sessionFactory, constantNode, out _, out var _persister, out _, out _) &&
575+
!_persister.EntityMetamodel.HasSubclasses)
575576
{
576577
return false;
577578
}

0 commit comments

Comments
 (0)