Я использую общий репозиторий /UoW в своем приложении С# Я использовал EF6, затем перешел на ядро EF. Мое приложение работало хорошо, за исключением того, что по какой-то причине мои включения не работают, и я получил исключение
Интерфейс:
TEntity GetFirstOrDefault(
Expression<Func<TEntity, bool>> filter = null,
params Expression<Func<TEntity, object>>[] includes);
Реализация (ядро EF):
public virtual TEntity GetFirstOrDefault(Expression<Func<TEntity, bool>> filter = null,
params Expression<Func<TEntity, object>>[] includes)
{
IQueryable<TEntity> query = dbSet;
query = includes.Aggregate(query, (current, item) => EvaluateInclude(current, item));
return query.FirstOrDefault(filter);
}
В Entity Framework EF6 это было:
foreach (Expression<Func<TEntity, object>> include in includes)
query = query.Include(include);
Функция EvaluateInclude:
private IQueryable<TEntity> EvaluateInclude(IQueryable<TEntity> current, Expression<Func<TEntity, object>> item)
{
if (item.Body is MethodCallExpression)
{
var arguments = ((MethodCallExpression)item.Body).Arguments;
if (arguments.Count > 1)
{
var navigationPath = string.Empty;
for (var i = 0; i < arguments.Count; i++)
{
var arg = arguments[i];
var path = arg.ToString().Substring(arg.ToString().IndexOf('.') + 1);
navigationPath += (i > 0 ? "." : string.Empty) + path;
}
return current.Include(navigationPath);
}
}
return current.Include(item);
}
Когда я вызываю функцию GetFirstOrDefault таким образом, она работает:
internal Domain.Entities.Project GetProject(int projectId)
{
Expression<Func<Domain.Entities.Project, bool>> funcWhere = j => (!j.IsDisabled && j.ProjectId == projectId);
return UnitOfWork.Repository<Domain.Entities.Project>().GetFirstOrDefault(funcWhere,
p => p.StatusProject,
p => p.ProjectRoles.Select(t => t.Employee),
//p => p.ProjectTeams.Select(t => t.Team.TeamEmployees.Select(e => e.Employee)),
);
}
Но когда я раскомментирую дополнительный include, он терпит неудачу:
internal Domain.Entities.Project GetProject(int projectId)
{
Expression<Func<Domain.Entities.Project, bool>> funcWhere = j => (!j.IsDisabled && j.ProjectId == projectId);
return UnitOfWork.Repository<Domain.Entities.Project>().GetFirstOrDefault(funcWhere,
p => p.StatusProject,
p => p.ProjectRoles.Select(t => t.Employee),
p => p.ProjectTeams.Select(t => t.Team.TeamEmployees.Select(e => e.Employee)),
);
}
System.InvalidOperationExceptionInvalid include path: 'Project.ProjectTeams.Team.TeamEmployees.Select(e => e.Employee)' - couldn't find navigation for: 'Select(e => e'
@KirkWoll отредактировано
Вы используете старый синтаксис Include
.
Вы уверены, что Team.TeamEmployees
правильно подключен к EF? Можно ли вообще использовать TeamEmployees
с запросами EF?
@KirkWoll, да. С EF6 все работало нормально, я получаю свой проект с projectTeam, у которого есть команда, а внутри команды есть сотрудники.
@GertArnold, не могли бы вы дать мне, как изменить его на новый?
Решено:
после этого ответа связь Я добавил этот код, который анализирует мое лямбда-выражение, включающее:
// This method is a slight modification of EF6 source code
private bool TryParsePath(Expression expression, out string path)
{
path = null;
var withoutConvert = RemoveConvert(expression);
var memberExpression = withoutConvert as MemberExpression;
var callExpression = withoutConvert as MethodCallExpression;
if (memberExpression != null)
{
var thisPart = memberExpression.Member.Name;
string parentPart;
if (!TryParsePath(memberExpression.Expression, out parentPart))
{
return false;
}
path = parentPart == null ? thisPart : (parentPart + "." + thisPart);
}
else if (callExpression != null)
{
if (callExpression.Method.Name == "Select"
&& callExpression.Arguments.Count == 2)
{
string parentPart;
if (!TryParsePath(callExpression.Arguments[0], out parentPart))
{
return false;
}
if (parentPart != null)
{
var subExpression = callExpression.Arguments[1] as LambdaExpression;
if (subExpression != null)
{
string thisPart;
if (!TryParsePath(subExpression.Body, out thisPart))
{
return false;
}
if (thisPart != null)
{
path = parentPart + "." + thisPart;
return true;
}
}
}
}
else if (callExpression.Method.Name == "Where")
{
throw new NotSupportedException("Filtering an Include expression is not supported");
}
else if (callExpression.Method.Name == "OrderBy" || callExpression.Method.Name == "OrderByDescending")
{
throw new NotSupportedException("Ordering an Include expression is not supported");
}
return false;
}
return true;
}
// Removes boxing
private Expression RemoveConvert(Expression expression)
{
while (expression.NodeType == ExpressionType.Convert
|| expression.NodeType == ExpressionType.ConvertChecked)
{
expression = ((UnaryExpression)expression).Operand;
}
return expression;
}
#endregion
Затем измените мою функцию ОценитьВключить на:
private IQueryable<TEntity> EvaluateInclude(IQueryable<TEntity> current, Expression<Func<TEntity, object>> item)
{
if (item.Body is MethodCallExpression)
{
string path;
TryParsePath(item.Body, out path);
return current.Include(path);
}
return current.Include(item);
}
И это работает
ошибка происходит в .Select(e=>e.Employee): не удалось найти навигацию для: Select(e=>e.Employee