Джойн с произвольным условием. Запрос к БД, принимающий фильтр в качестве параметра

Есть два солюшена: в одном .Net Framework и NHibernate, во втором .Net Core 3 и EF Core.

Есть задача: написать запрос с Join'ом к БД, который будет принимать фильтр в качестве параметра. Джойнятся сущности одной таблицы по свойству, которое просто числовое, никаких внешних ключей или связей один к одному. (По сути у нас есть черновая и актуальная версии сущности и в этом свойство хранится Id'шник актуальной, чтобы была возможность связать их).

Во втором проекте (с EF Core) сработал следующий LINQ запрос:

public async Task ApproveByPredicateAsync(Expression<Func<DraftAndApproved<TEntity>, bool>> predicate)
{
    var draftsForApprove = await Query<T>() //IQueryable<T>
        .Join(Query<T>(),
            draft => draft.EntityId,
            approved => approved.EntityId,
            (draft, approved) => new DraftAndApproved<TEntity> { Draft = draft, Approved = approved })
        .Where(predicate)
        .Select(da => da)
        .ToArrayAsync();

    //other actions...
}

//somewhere above
public struct DraftAndApproved<TEntity>
{
    public TEntity Draft { get; set; }

    public TEntity Approved { get; set; }

    public void Deconstruct(out TEntity draft, out TEntity approved)
    {
        draft = Draft;
        approved = Approved;
    }
}

Но NHibernate ругается на NotSupported для подобного Join'а (а ещё до этого для него структуру пришлось переделать в класс, ибо иначе он не видел пустой конструктор). С GroupJoin аналогичная история. Провал маппить в анонимный класс, а потом Select'ить перед Where, но тоже не сработало.

Пытался понять как такое написать на QueryOver, но там нет адекватного решения для Join'а не связанных друг с другом сущностей.

В варианте с Expression я мапплю в явный класс, чтобы можно было сигнатуру для входящего аргумента задать, иначе не понятно что просить на вход в Where.

Думал переписать запрос на DetachedCriteria, но опять же не могу понять как с её помощью написать джойн для не связанных сущностей: CreateCriteria требует от меня path, которого у меня нет.

Пытался написать CreateSqlQuery, но не понял как смаппить результат.

Session.CreateSQLQuery($@"
    SELECT draft.*, approved.*
    FROM {typeof(T).Name} draft
    LEFT JOIN {typeof(T).Name} approved
        ON draft.EntityState = 3
        AND approved.EntityState = 1
        AND draft.EntityId = approved.EntityId
        AND draft.Version != approved.Version
    WHERE {filter}
")

Всё упирается в то, что, как мне показалось, NHibernate не умеет джойнить не связанные сущности или даже хоть как-то работать с подобными запросами.

Попробовал такой вариант, но он падает в NRE на Select'ах. Видимо не проджектится адекватно.

T draftAl = null;
T approvedAl = null;
DraftAndApproved<T> dto = null;

var draftsForApproveObj = Session.QueryOver(null, () => draftAl)
    .JoinEntityAlias(() => approvedAl,
        () => approvedAl.EntityId == draftAl.EntityId,
        JoinType.LeftOuterJoin)
    .Where(filter)
    .SelectList(list => list
        .Select(x => draftAl).WithAlias(() => dto.Draft)
        .Select(x => approvedAl).WithAlias(() => dto.Approved))
    .TransformUsing(Transformers.AliasToBean<DraftAndApproved<T>>())
    .List<DraftAndApproved<T>>();


System.NullReferenceException: Object reference not set to an instance of an object.
   at NHibernate.Criterion.ConstantProjection..ctor(Object value)
   at NHibernate.Criterion.Projections.Constant(Object obj)
   at NHibernate.Impl.ExpressionProcessor.FindMemberProjection(Expression expression)
   at NHibernate.Criterion.Lambda.QueryOverProjectionBuilder`1.Select(Expression`1 expression)
   at Granit.Cssp.Controllers.Productions.ProductionMigrationController.<>c__DisplayClass13_0`1.<ApproveItemsByPredicate>b__3(QueryOverProjectionBuilder`1 list)
   at NHibernate.Criterion.QueryOver`2.NHibernate.IQueryOver<TRoot,TSubType>.SelectList(Func`2 list)
   at Granit.Cssp.Controllers.Productions.ProductionMigrationController.ApproveItemsByPredicate[T](DataScope ds, Expression`1 filter)

Ответы (0 шт):