web-dev-qa-db-fra.com

C # Dynamic Linq: implémentez "Like" dans la clause Where

Je veux donc faire un trieur général pour mes données. J'ai ce code pour obtenir des données de la base de données qui extraira uniquement les données qui contiennent value.

using System.Linq.Dynamic;

public static IQueryable<object> SortList(string searchString, Type modelType, 
    IQueryable<object> model)
{
    ....

    string toStringPredicate = type == typeof(string) ? propertyName + 
        ".Contains(@0)" : propertyName + ".ToString().Contains(@0)";
    model = model.Where(propertyName + " != NULL AND " + toStringPredicate, value);
}

Le modèle est le suivant:

public class ManageSubscriberItems
{
    public int? UserId { get; set; }
    public string Email { get; set; }
    public Guid SubscriberId { get; set; }
}

Quand j'appelle:

models = (IQueryable<ManageSubscriberItems>)EcommerceCMS.Helpers.FilterHelper
    .SortList(searchString, typeof(ManageSubscriberItems), models);

if(models.Any())

Il jette cette erreur:

"LINQ to Entities ne reconnaît pas la méthode 'System.String ToString ()', et cette méthode ne peut pas être traduite en une expression de magasin."


ÉDITER

J'ai trouvé le problème, mais je ne peux toujours pas le résoudre. Donc, si la propriété n'est pas string, elle générera une erreur lors de l'appel de .ToString().Contains().

model = model.Where(propertyName + " != NULL AND " + propertyName + 
    ".ToString().Contains(@0)", value);

Ce que je veux, c'est implémenter LIKE dans la requête. Quelqu'un peut-il m'aider?

10
Alvin Stefanus

Si vous utilisez System.Linq.Dynamic.Core avec EF Core , vous avez la possibilité d'utiliser

var q = context.Cars.Where(config, "DynamicFunctions.Like(Brand, \"%a%\")");

Voir ce lien pour un exemple: https://github.com/StefH/System.Linq.Dynamic.Core/blob/6fc7fcc43b248940560a0728c4d181e191f9eec1/src-console/ConsoleAppEF2.1.1/Program.cs#L117

Et je viens de tester dans linqpad la connexion à une vraie base de données, et un code comme celui-ci fonctionne?

var result1 = Entity1s.Where("Url != NULL AND it.Url.Contains(@0)", "e");


[MISE À JOUR 2019-04-17]]

Dans le cas où vous ne connaissez pas le type, vous pouvez le convertir en objet , puis le convertir en chaîne .

Code:

var r = Entity1s.Select("string(object(Rating))").Where("Contains(@0)", "6");
9
Stef Heyenrath

donc le problème ici est que IQueryable quelque chose se passe sur le serveur SQL pas en C # ... donc SQL le serveur ne sait rien de la méthode . toString (). so => ​​et comme opérateur il fonctionne automatiquement sur les chaînes .. il s'agit donc des types de données nvarchar et varchar dans SQL Server. Je pourrais vous donner un exemple de la manière d'y parvenir si vous pouviez m'en dire plus sur votre problème et ce que vous voulez accomplir. pourrait faire un échantillon.

4
Edgars Salmiņš

Vous avez déjà un "Like" dans Linq qui peut fonctionner dans la base de données et fonctionne avec des chaînes, il s'appelle "IndexOf":

 ((IQueryable)model).Where(m => m.Property.IndexOf(searchString) == 1);

Selon MSDN: IndexOf (string)

' Position d'index de base zéro de la valeur si cette chaîne est trouvée, ou -1 si elle ne l'est pas. Si la valeur est vide, la valeur de retour est 0. '

0
Diogo Neves

Je veux donc faire un trieur général pour mes données.

au lieu de corriger 'invoke issue' , la manière générale devrait utiliser des génériques, comme

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, 
                                       string property,
                                       bool asc = true) where T : class
{
    //STEP 1: Validate MORE!
    var searchProperty = typeof(T).GetProperty(property);
    if (searchProperty == null) throw new ArgumentException("property");

     ....

    //STEP 2: Create the OrderBy property selector
    var parameter = Expression.Parameter(typeof(T), "o");
    var selectorExpr = Expression.Lambda(Expression.Property(parameter, property), parameter)        

    //STEP 3: Update the IQueryable expression to include OrderBy
    Expression queryExpr = source.Expression;
    queryExpr = Expression.Call(typeof(Queryable), asc ? "OrderBy" : "OrderByDescending",
                                  new Type[] { source.ElementType, searchProperty.PropertyType },
                                 queryExpr, 
                                selectorExpr);

    return source.Provider.CreateQuery<T>(queryExpr);
}

ayant une chaîne de nom de propriété et une direction généralement utilisées pour effectuer le "tri des colonnes" sur les données.

Viennent ensuite les prédicats de relation, et 'Linq.Dynamic' semble raisonnable quand on le fait à partir de zéro, mais il existe une forme générique et canonique existe .

0
valerysntx