EF Core 包括其他实体(通用存储库模式)
EF Core Including Other Entities (Generic Repository pattern)
我在我的应用程序 c# 中使用通用存储库/UoW patter
我使用的是 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'
已解决:
关注这个答案link
我添加了解析我的 lambda 表达式的代码 includes :
// 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
然后将我的 EvaluateInclude 函数更改为:
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);
}
而且有效
我在我的应用程序 c# 中使用通用存储库/UoW patter 我使用的是 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'
已解决:
关注这个答案link 我添加了解析我的 lambda 表达式的代码 includes :
// 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
然后将我的 EvaluateInclude 函数更改为:
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);
}
而且有效