web-dev-qa-db-fra.com

Comment utiliser Dapper avec Linq

J'essaie de convertir d'Entity Framework en Dapper pour, espérons-le, améliorer les performances d'accès aux données.

Les requêtes que j'utilise sont sous forme de prédicats comme "Expression>".

Pour donner un exemple:

J'ai le code suivant que je dois convertir en utilisant Dapper.

Ce que je fais actuellement:

public async Task<List<TModel>> Get(Expression<Func<TModel, bool>> query)
{
    // this.Context is of type DbContext
    return await this.Context.Set<TModel>().Where(query).ToListAsync();
}

Ce que j'aimerais faire:

public async Task<List<TModel>> Get(Expression<Func<TModel, bool>> query)
{
    using (IDbConnection cn = this.GetConnection)
    {
        return await cn.QueryAsync<TModel>(query);
    }
}

Mon google-fu me fait défaut, quelqu'un peut-il m'aider.

Éditer:

Notez que j'ai trouvé: https://github.com/ryanwatson/Dapper.Extensions.Linq

mais je n'arrive pas à comprendre comment l'utiliser.

8
Rian Mostert

Tout d'abord, l'un des auteurs de Dapper a déclaré, lorsque quelqu'un a demandé

Existe-t-il un plan pour rendre Dapper.net compatible avec les interfaces IQueryable?

cette

il n'est pas prévu de le faire. C'est bien loin de ce que dapper essaie de faire. Jusqu'à présent, je dirais que c'est antithétique. Le noyau Dapper essaie d'être l'ami de ceux qui aiment leur SQL.

(voir https://stackoverflow.com/a/27588877/3813189 ).

D'une certaine manière, cela suggère que les différents packages d'extension de NuGet peuvent aider, comme vous l'avez suggéré.

J'ai essayé DapperExtensions , ce qui facilite un peu la programmation des filtres de requête - par exemple.

using System.Data.SqlClient;
using DapperExtensions;

namespace StackOverflowAnswer
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var cn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
            {
                var list = cn.GetList<Products>(
                    Predicates.Field<Products>(f => f.Discontinued, Operator.Eq, false)
                );
            }
        }

        class Products
        {
            public int ProductId { get; set; }
            public string ProductName { get; set; }
            public bool Discontinued { get; set; }
        }
    }
}

J'ai également essayé Dapper.Extensions.Linq (le package que vous avez suggéré), ce qui promet de

s'appuie sur cela pour fournir un accès avancé à la base de données via des requêtes Linq. La configuration fluide rend la configuration simpliste et rapide.

Malheureusement, je n'ai pas pu aller très loin. Il n'y a pas beaucoup de documentation et les tests ne semblent pas couvrir le QueryBuilder, qui semble être la classe à utiliser pour traduire les expressions Linq dans les prédicats des extensions Dapper (comme suggéré par le problème Analyse des expressions booléennes) avec QueryBuilder ). J'ai essayé ce qui suit, ce qui nécessitait d'ajouter l'interface IEntity à mon DTO -

using System;
using System.Data.SqlClient;
using System.Linq.Expressions;
using Dapper.Extensions.Linq.Builder;
using Dapper.Extensions.Linq.Core;
using DapperExtensions;

namespace StackOverflowAnswer
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var cn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
            {
                Expression<Func<Products, bool>> filter = p => !p.Discontinued;
                var queryFilter = QueryBuilder<Products>.FromExpression(filter);

                var list = cn.GetList<Products>(
                    queryFilter
                );
            }
        }

        class Products : IEntity
        {
            public int ProductId { get; set; }
            public string ProductName { get; set; }
            public bool Discontinued { get; set; }
        }
    }
}

.. mais il a échoué à l'exécution avec l'erreur

Opérateur introuvable pour les produits StackOverflowAnswer.Program +

Je ne sais pas pourquoi la génération manuelle du prédicat (le premier exemple) fonctionne mais QueryBuilder ne fonctionne pas ..

Je dirais qu'il semble de plus en plus que les commentaires laissés sur votre question sont corrects, que vous devrez retravailler votre code loin des expressions que vous avez utilisées avec Entity Framework. Comme il a été si difficile de trouver des informations sur cette classe QueryBuilder, je craindrais que (même si vous le faisiez fonctionner) les problèmes que vous rencontriez seraient difficiles à obtenir de l'aide (et les bogues pourraient ne pas être corrigés).

15
Dan Roberts

J'ai écrit un utilitaire pour travailler EF avec Dapper en utilisant des attributs. J'analyse le prédicat et le traduis en SQL.

POCO "Utilisateurs":

[Table("Users")]
public class User
{
    [Key]
    [Identity]
    public int Id { get; set; }

    public string Login { get; set;}

    [Column("FName")]
    public string FirstName { get; set; }

    [Column("LName")]
    public string LastName { get; set; }

    public string Email { get; set; }

    [NotMapped]
    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", FirstName, LastName);
        }
    }
}

Et requête simple:

using (var cn = new SqlConnection("..."))
{
    var usersRepository = new DapperRepository<User>(cn)
    var allUsers = await userRepository.FindAllAsync(x => x.AccountId == 3 && x.Status != UserStatus.Deleted);
}

Peut-être que cela vous sera utile?

MicroOrm.Dapper.Repositories

9
Sergey Kuznetsov