Comment remplacer le type de propriété et sa valeur dans les arbres d'expression

c# expression-trees

Question

J'ai une classe PersonDTO avec la propriété Nullable DateTime:

public class PersonDTO
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    // YYYYMMDD format
    public virtual Nullable<int> Birthday { get; set; }
}

Et une classe dans la couche de présentation:

public class PersonDTO
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    // YYYYMMDD format
    public virtual Nullable<int> Birthday { get; set; }
}

Sur mon formulaire, j'ai deux méthodes responsables de la création de l' Expression<Func<PersonViewModel, bool>> object:

public class PersonDTO
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    // YYYYMMDD format
    public virtual Nullable<int> Birthday { get; set; }
}

Aussi, j'utilise AutoMapper? qui convertit une Expression<Func<PersonViewModel, bool>> en Expression<Func<PersonDTO, bool>> . Le code de conversion ressemble à:

public class PersonDTO
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    // YYYYMMDD format
    public virtual Nullable<int> Birthday { get; set; }
}

Mon convertisseur d'expression ressemble à ceci:

public class PersonDTO
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    // YYYYMMDD format
    public virtual Nullable<int> Birthday { get; set; }
}

J'ai besoin d'une certaine manière de convertir une partie d'une expression lambda: person => person.Birthday > Convert(15.11.2016 00:00) (dans ce cas, la personne est PersonViewModel et Birthday de type DateTime?) En quelque chose qui ressemble à: person => person.Birthday > 20161115 (dans ce cas, il s'agit de PersonDTO et Birthday de type int?). Sans ce problème, tout fonctionne correctement. Je comprends que je dois aller plus loin dans l’arbre et faire quelques manipulations, mais je ne comprends pas comment et où dois-je faire cela.

Réponse populaire

Je voudrais adapter la valeur de la date et l'heure sur les expressions binaires avec sg le long:

class AutoMapVisitor<TSource, TDestination>: ExpressionVisitor
{
    // your stuff
    protected override Expression VisitBinary(BinaryExpression node)
    {
        var memberNode = IsBirthdayNode(node.Left)
            ? node.Left
            : IsBirthdayNode(node.Right)
                ? node.Right
                : null;
        if (memberNode != null)
        {
            var valueNode = memberNode == node.Left
                ? node.Right
                : node.Left;
            // get the value
            var valueToChange = (int?)getValueFromNode(valueNode);
            var leftIsMember = memberNode == node.Left;
            var newValue = Expression.Constant(DataTypesExtensions.NullIntToNullDateTime(valueToChange, /*insert your format here */ ""));
            var newMember = Visit(memberNode);
            return Expression.MakeBinary(node.NodeType, leftIsMember ? newMember : newValue, leftIsMember ? newValue : newMember); // extend this if you have a special comparer or sg
        }
        return base.VisitBinary(node);
    }

    private bool IsBirthdayNode(Expression ex)
    {
        var memberEx = ex as MemberExpression;
        return memberEx != null && memberEx.Member.Name == "Birthday" && memberEx.Member.DeclaringType == typeof(PersonViewModel);
    }

    private object getValueFromNode(Expression ex)
    {
        var constant = ex as ConstantExpression;
        if (constant != null)
            return constant.Value;
        var cast = ex as UnaryExpression;
        if (cast != null && ex.NodeType == ExpressionType.Convert)
            return getValueFromNode(cast.Operand);
        // here you can add more shortcuts to improve the performance of the worst case scenario, which is:
        return Expression.Lambda(ex).Compile().DynamicInvoke(); // this will throw an exception, if you have references to other parameters in your ex
    }

}

c'est assez spécifique, mais vous avez l'idée, et vous pouvez le rendre plus générique pour vos cas d'utilisation.

Mais je pense que votre cartographie de la propriété est fausse. En SQL, vous voulez utiliser la comparaison int. Ce qui précède le fait pour vous. Lorsque l'automapper modifie vos propriétés, il convient simplement de remplacer l'ancien anniversaire par le nouveau (changer de type), sans l'appel de NullDateTimeToNullInt. Le code ci-dessus prendra en charge le changement de type pour les comparaisons. Si vous avez le membre en sélection anonyme ou d'autres endroits, vous aurez toujours un problème, je crois ...




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi