Резюме: Я хочу знать, как я могу определить конкретные определения из тела выражения и затем изменить его так, как я хочу, например,
e.Entity.ListA.Union(e.ListB).Any(...)...
На
e.Entity != null &&
((e.Entity.ListA != null && e.Entity.ListA.Any(...))
|| (e.Entity.ListB != null && e.Entity.ListB.Any(...)))
Только использование техник Linq Expression, как я вижу, является идеальным решением
В рамках написания чистого кода на C # я написал набор предопределенных выражений и с помощью расширений LinqKit, которые я могу комбинировать междуих, следовательно, это расширит динамизм написания сложных выражений легко, пока все не будет в порядке. Кроме того, я хочу использовать их для фильтрации случаев IQuerable и IEnumerable. Однако, как вы знаете, в некоторых случаях определенное выражение не будет работать ни в Former, ни в последнем, я успешно избежал многих таких проблем. Пока я не дошел до случая, когда я принял решение, но я все еще чувствую, что это не идеал.
Сначала я начну с показа проблемы, затем объясню желаемое решение, в конце я поделюсь своимпопытка.
//---
public class AssignmentsEx : BaseEx
{
//.........
/// <summary>
/// (e.FreeRoles AND e.RoleClass.Roles) ⊆ ass.AllRoles
/// </summary>
public static Expression<Func<T, bool>> RolesInclosedBy<T>(IAssignedInstitution assignedInstitution) where T : class, IAssignedInstitution
{
var allStaticRoles = AppRolesStaticData.AdminRolesStr.GetAll();
var assAllRoles = assignedInstitution.AllRoles.Select(s => s.Name).ToList();
var hasAllRoles = allStaticRoles.All(assR => assAllRoles.Any(sR => sR == assR));
if (hasAllRoles)
return e => true;
// for LINQ to SQL the expression works perfectly as you know
// the expression will be translated to an SQL code
// for IEnumerable case the nested object Roles with throw null obj ref
// exception if the RoleClass is null (and this is a healthy case from code execution
//
return Expression<Func<T, bool>> whenToEntity = e => e.FreeRoles.Union(e.RoleClass.Roles).All(eR => assAllRoles.Any(assR => assR == eR.Name));
}
//.........
}
Как видите, если я использую этот метод, чтобы определить список объектов с RoleClass равен нулю или FreeRoles равен нулю, то будет выброшено исключение NullException.
- лучшее -ожидаемое предположение Я думаю, что это будет играть на три фактора:
возможность обнаружить нужный фрагмент из тела выражения
изменить фрагмент, чтобы бытьпо мере необходимости для случая IEnumerable или наоборот
реконструировать и вернуть новое выражение
таким образом, я буду поддерживать метод статичным и изменятьэто с помощью метода расширения: например, ex.WithSplittedUnion ()
, а не традиционным способом, т.е. я использую сейчас, как следует
public class AssignmentsEx
{
public LinqExpressionPurpose purpose{get;}
public AssignmentsEx(LinqExpressionPurpose purpose) : base(purpose)
{
Purpose = purpose
}
public Expression<Func<T, bool>> RolesInclosedBy<T>(IAssignedInstitution assignedInstitution) where T : class, IAssignedInstitution
{
var allStaticRoles = AppRolesStaticData.AdminRolesStr.GetAll();
var assAllRoles = assignedInstitution.AllRoles.Select(s => s.Name).ToList();
var hasAllRoles = allStaticRoles.All(assR => assAllRoles.Any(sR => sR == assR));
if (hasAllRoles)
return e => true;
Expression<Func<T, bool>> whenToObject = e => (e.FreeRoles == null || e.FreeRoles.All(eR => assAllRoles.Any(assR => assR == eR.Name)))
&& (e.RoleClass == null || e.RoleClass.Roles == null || e.RoleClass.Roles.All(eR => assAllRoles.Any(assR => assR == eR.Name)));
Expression<Func<T, bool>> whenToEntity = e => e.FreeRoles.Union(e.RoleClass.Roles).All(eR => assAllRoles.Any(assR => assR == eR.Name));
return Purpose switch
{
LinqExpressionPurpose.ToEntity => whenToEntity,
LinqExpressionPurpose.ToObject => whenToObject,
_ => null,
};
}
}
Я надеюсь, что объяснение понятно, заранее спасибо