У меня есть следующий фрагмент:
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]
))