J'ai une classe représente un objet de filtre génériqueManipulation des références nullables lors de la construction LambdaExpression dynamiquement
public class Filter
{
public string column { get; set; }
public string operator { get; set; }
public string data { get; set; }
}
que je suis capable de transformer en un LambdaExpression
grâce au code comme celui-ci
public LambdaExpression ToExpression(IQueryable query) {
LambdaExpression toReturn = null;
ParameterExpression parameter = Expression.Parameter(query.ElementType, "p");
MemberExpression memberAccess = GetMemberExpression(column, parameter);
ConstantExpression filter = Expression.Constant(Convert.ChangeType(data, memberAccess.Type));
WhereOperation condition = (WhereOperation)StringEnum.Parse(typeof(WhereOperation), operator);
LambdaExpression lambda = BuildLambdaExpression(memberAccess, filter, parameter, condition, data);
if (toReturn == null) {
toReturn = lambda;
}
return toReturn;
}
Conformément à la Le membre Filter
column
peut contenir une sorte de sintax de navigation pour faire des requêtes qui est exprimée comme FieldA.FieldB.Description
qui se traduit par:
- Obtenir la valeur de type T retourné de la propriété FieldA
- Obtenir la valeur de type T1 renvoyée par le FieldB de T
- Obtenir la valeur de type T2 sont retournés à partir de la description de T2
le résultat est un lambda comme celui-ci: p.FieldA.FieldB.Description == "data"
et je peut utiliser ce résultat en tant que paramètre de la méthode d'extension Where
quelle IQueryable
Le problème se produit lorsque l'un des membres de la requête de navigation est de type Nullable
. Dans ce cas, en supposant FieldA est annulable, le lambda correcte doit être
p.FieldA != null && p.FieldA.FieldB.Description == "data"
J'ai essayé de mettre en oeuvre cette vérification lors de la construction de l'objet MemberExpression
en utilisant le code comme celui-ci
MemberExpression memberAccess = null;
foreach (var property in column.Split('.')) {
memberAccess = MemberExpression.Property(memberAccess ?? (p as Expression), property);
Type memberType = memberAccess.Type;
if (memberType.IsGenericType &&
memberType.GetGenericTypeDefinition() == typeof(Nullable<>)) {
//Create here an expression of type : memberAccess != null
}
}
qui est bon pour les types primitifs mais ne fonctionne pas, par exemple, avec d'autres références d'objet, comme les instances d'objet EF EntityReference
. Je sais que je pourrais simplement ajouter une autre condition à la précédente if
comme
if ((memberType.IsGenericType &&
memberType.GetGenericTypeDefinition() == typeof(Nullable<>)) ||
memberType.IsClass) {
}
mais qui me semble trop générique produire un lambda avec trop de condition et la plupart d'entre eux unuseful peut-être.
Y a-t-il un moyen de mieux identifier les références nullables?
Si l'expression est destinée à Entity Framework, je ne voudrais pas déranger. 'p.FieldA.FieldB.Description ==" data "' sera simplement faux sans aucune exception si 'FieldA' ou' FieldB' est nul. Si c'est destiné à être compilé et exécuté en mémoire, c'est une autre histoire. –
J'utilise la première version d'EF, celle qui fonctionne avec .NET 3.5. Si je fais une requête comme dans l'exemple, la requête ne s'applique tout simplement pas et le résultat est comme si je n'avais spécifié aucun filtre ... – Lorenzo