Inline If-Else выдает System.ArgumentException: типы аргументов не совпадают - PullRequest
1 голос
/ 01 октября 2019

У меня есть следующий фрагмент:

var a = dbContext.Employees.AsQueryable();
var b = dbContext.Employees.Where(x => x.IsManager == 1);
var results = dbContext.Companies
                       .SelectMany(x => x.IsActive == 1 ? a : b)
                       .Select(x => x.Id);

Я думал, что он будет выполняться без каких-либо проблем, но интересно, я получил эту ошибку:

fail: Microsoft.AspNetCore. Server.Kestrel [13] Идентификатор соединения "0HLQ6AD1S5ITB", Идентификатор запроса "0HLQ6AD1S5ITB: 00000001": Приложение сгенерировало необработанное исключение. System.ArgumentException: типы аргументов не совпадают в System.Linq.Expressions.Expression.Condition (тест выражения, выражение ifTrue, выражение ifFalse, тип type) в System.Linq.Expressions.ConditionalExpression.Update (тест выражения, выражение ifTrue, выражениеifFalse) в System.Linq.Expressions.ExpressionVisitor.VisitConditional (узел ConditionalExpression) в System.Linq.Expressions.ConditionalExpression.Accept (посетитель ExpressionVisitor) в System.Linq.Expressions.ExpressionVisitor.Visit (узел Expression) в Microsoft.EntityFrame.EntityQueryModelVisitor.ReplaceClauseReferences (выражение Выражение, IQuerySource querySource, булева inProjection) при Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CompileAdditionalFromClauseExpression (additionalFromClause additionalFromClause, QueryModel queryModel) при Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.CompileAdditionalFromClauseExpression (additionalFromClause additionalFromClause, ЗапросМодель queryModel) при Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitAdditionalFromClause (AdditionalFromClause fromClause, QueryModel queryModel, индекс Int32) при Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitAdditionalFromClause (AdditionalFromClause fromClause, QueryModel queryModel, индекс Int32) при Remotion.Linq.Clauses. AdditionalFromClause.Accept (IQueryModelVisitor посетитель, QueryModel queryModel, индекс Int32) в Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses (ObservableCollection`1 bodyClauses, QueryModel queryModel) в Remotion.Linq.QueryModelVisitorBase.VisitQueryModel (QueryModel queryModel) в Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel (QueryModel queryModel) в Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel (QueryModel queryModel) в Microsoft.EntityFrameworkCore.Query.ElityQueryMeraMateCateMateCateMateCateMateCateMateCateMateCateMateCateMateCateMateCateMateCateMateore.Storage.Database.CompileQuery [TResult] (QueryModel queryModel)

Я не уверен, что здесь не так, тем более что этот фрагмент прекрасно работает с правильными результатами:

var a = dbContext.Employees.AsQueryable();
var results = dbContext.Companies
                       .SelectMany(x => a)
                       .Select(x => x.Id);

и только этот отрыванный код работает нормально:

var b = dbContext.Employees.Where(x => x.IsManager == 1);
var results = dbContext.Companies
                       .SelectMany(x => b)
                       .Select(x => x.Id);

PS Я использую EF Core 2.2


ОБНОВЛЕНИЕ 1

Хорошо, я пытался упростить свою проблему с помощью приведенного выше примера, но я думаю, что это не очень хорошая идея.

Итак, вот что у меня есть: три основных объекта: Post, Employee и WorkGroup и три объекта отображения: EmployeeWorkGroup, PostEmployee и PostWorkGroup,Шесть сущностей имеют следующую реализацию:

class Post {
    public Guid Id { get; set; }
    public int IsGlobal { get; set; }
    public virtual ICollection<PostEmployee> Employees { get; set; }
    public virtual ICollection<PostWorkGroup> WorkGroups { get; set; }
}

class Employee {
    public Guid Id { get; set; }
}

class WorkGroup {
    public Guid Id { get; set; }
    public Guid? ParentId { get; set; }
    public string Prefix { get; set; }
}

class EmployeeWorkGroup {
    public Guid EmployeeId { get; set; }
    public Guid WorkGroupId { get; set; }
    public virtual Employee Employee { get; set }
    public virtual WorkGroup WorkGroup { get; set; }
}

class PostEmployee {
    public Guid EmployeeId { get; set; }
    public Guid PostId { get; set; }
    public virtual Employee Employee { get; set }
    public virtual Post Post { get; set; }
}

class PostWorkGroup {
    public Guid WorkGroupId { get; set; }
    public Guid PostId { get; set; }
    public virtual WorkGroup WorkGroup { get; set; }
    public virtual Post Post { get; set; }
}

Проще говоря, основная цель - отправлять сообщения сотрудникам либо непосредственно им (используя PostEmployee сущность), по рабочим группам: (используя EmployeeWorkGroupи PostWorkGroup), или всем сотрудникам (установив IsGlobal из Post в 1).

Мне удалось сделать выше, теперь я хочу получить сотрудников данной должности. Сложность заключается в том, что мне нужно собирать их из назначенных рабочих групп (которые являются иерархическими) (с использованием EmployeeWorkGroup и PostWorkGroup) и у сотрудников почты (с использованием сущности PostEmployee). Если сообщение было отправлено каждому (т. Е. IsGlobal равно 1), мне нужно вернуть всех сотрудников.

Это моя текущая попытка:

// get all employee ids from the posts work groups
Expression<Func<Post, IEnumerable<Guid>>> postEmployeesFromWorkGroups = post =>
    allWorkGroups
        .Where(workGroup => post.WorkGroups
            .Any(postWorkGroup => workGroup.Prefix.StartsWith(postWorkGroup.WorkGroup.Prefix)))
        .SelectMany(y => y.Employees
            .Where(z => !post.Employees.Any(b => b.EmployeeId.Equals(z.EmployeeId))))
        .Select(y => y.EmployeeId)
        .Distinct();

// get all employee ids from posts' immediate employees list
Expression<Func<Post, IEnumerable<Guid>>> postEmployees = post => post.Employees.Select(x => x.EmployeeId);

// return the results
public static Expression<Func<Post, IEnumerable<Employee>>> var predicate = post => post.IsGlobal == 1
    ? allEmployees
    : allEmployees.Where(x =>
        postEmployeesFromWorkGroups.Invoke(post).Contains(x.Id) ||
        postEmployees.Invoke(post).Contains(x.Id));


db.Posts.AsExpandable().Where(x=>x.Id.Equals("some-id")).Select(predicate);

Без условияЯ могу выполнить любую сторону if-else без нареканий.

PS Я использую LinqKit.


ОБНОВЛЕНИЕ 2

Это запрос, который я получаю, выполняя приведенный выше код (я удалил одну из сторон if, чтобы заставить его работать):

SELECT [x0].[id]
FROM [posts] AS [x]
CROSS JOIN [employees] AS [x0]
WHERE (([x].[is_deleted] <> 1) AND ([x0].[is_deleted] <> 1)) AND ([x0].[id] IN (
  SELECT DISTINCT [workGroup.Employees].[employee_id]
  FROM [work_groups] AS [x1]
  INNER JOIN [employees_work_groups] AS [workGroup.Employees] ON [x1].[id] = [workGroup.Employees].[work_group_id]
  WHERE (([x1].[is_deleted] <> 1) AND EXISTS (
      SELECT 1
      FROM [work_groups_posts] AS [postWorkGroup]
      INNER JOIN (
          SELECT [x2].*
          FROM [work_groups] AS [x2]
          WHERE [x2].[is_deleted] <> 1
      ) AS [t] ON [postWorkGroup].[work_group_id] = [t].[id]
      WHERE (([x1].[prefix] LIKE [t].[prefix] + N'%' AND (LEFT([x1].[prefix], LEN([t].[prefix])) = [t].[prefix])) OR ([t].[prefix] = N'')) AND ([x].[id] = [postWorkGroup].[post_id]))) AND NOT EXISTS (
      SELECT 1
      FROM [employees_posts] AS [b]
      WHERE ([b].[employee_id] = [workGroup.Employees].[employee_id]) AND ([x].[id] = [b].[post_id]))
) OR [x0].[id] IN (
  SELECT [x3].[employee_id]
  FROM [employees_posts] AS [x3]
  WHERE [x].[id] = [x3].[post_id]
))
...