Dapper en .Net Core

I. Introducción

  Acerca de lo que es Dapper, no entraré en detalles aquí; este artículo solo describe brevemente el uso de Dapper en .Net Core. El código presentado se basa principalmente en ejemplos, y es solo una guía. Los desarrolladores pueden expandir y ajustar según a sus propias necesidades; Si hay alguna omisión, no dude en corregirla.

2. Construcción de ambiente elegante

Actualmente, tomando como ejemplo el proyecto .Net Core WebAPI o MVC, la versión del marco es .NET 5.0 y las referencias relevantes del paquete NuGet son las siguientes:

Paquete de instalación Dapper

Paquete de instalación Dapper.Contrib

Paquete de instalación Dapper.SqlBuilder

Paquete de instalación System.Data.SqlClient

Entre ellos, Dapper.Contrib y Dapper.SqlBuilder son extensiones de Dapper. Por supuesto, las extensiones de Dapper incluyen otros paquetes como Dapper.Rainbow, a los que se puede hacer referencia de acuerdo con sus propias necesidades, y las referencias relevantes se explican a continuación:

  • Dapper: No hace falta decirlo;
  • Dapper.Contrib: puede usar objetos para agregar, eliminar, modificar y consultar tablas de datos, evitando la necesidad de escribir declaraciones SQL;
  • Dapper.SqlBuilder: Es conveniente construir dinámicamente sentencias SQL, como Join, SELECT, Where, OrderBy, etc.;
  • System.Data.SqlClient: dado que la base de datos de ejemplo es Sql Server, como MySql, consulte MySql.Data;


Para las opciones de configuración de la entidad Dapper.Contrib, tomando como ejemplo la clase Product, una breve descripción es la siguiente:

[Table("Product")]
public class Product
{
    [Key]  
    public int Id { get; set; }
    public string Name{ get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public DateTime CreateTime { get; set; }
}

Para los elementos de configuración de la entidad, existen los siguientes elementos principales:

  • Tabla: especifique el nombre de la tabla de la base de datos, que se puede ignorar;
  • Clave: designada como la clave principal de incremento automático;
  • ExplicitKey: especifique una clave principal que no crezca automáticamente, como GUID;
  • Calculado: atributo de columna calculado, que será ignorado por las operaciones de inserción y actualización;
  • Escribir: si se puede escribir, verdadero/falso, como [Escribir (falso)], cuando es falso, las operaciones Insertar y Actualizar ignorarán esta columna, por ejemplo, la clase parcial extensible se usa como un campo de consulta adicional en el tabla de datos;

Para la entidad objeto de la tabla de datos, se puede generar en combinación con la plantilla T4.

3. Paquete elegante

Realice modificaciones para ajustar el paquete de la siguiente manera:

Definir la clase DapperDBContext

 Ver código

 Ver código

El código anterior cubre las operaciones básicas de acceso de Dapper a la base de datos, divididas en síncronas y asíncronas, la mayoría de las cuales no se repetirán, enfocándose en la siguiente parte de paginación;

Construcción de paginación asíncrona (PageAsync)

Para la conveniencia de la paginación, solo necesita pasar la declaración Sql para ser consultada (como: SELECT * FROM Table, debe incluir Order BY), índice de página y tamaño de página;

En cuanto a cómo construirlo, consulte PetaPoco, una pequeña herramienta ORM, y extraiga el código relevante de la siguiente manera. Los estudiantes interesados ​​también pueden transformarlo por sí mismos:

public class Page<T>
    {
        /// <summary>
        /// The current page number contained in this page of result set 
        /// </summary>
        public long CurrentPage { get; set; }

        /// <summary>
        /// The total number of pages in the full result set
        /// </summary>
        public long TotalPages { get; set; }

        /// <summary>
        /// The total number of records in the full result set
        /// </summary>
        public long TotalItems { get; set; }

        /// <summary>
        /// The number of items per page
        /// </summary>
        public long ItemsPerPage { get; set; }

        /// <summary>
        /// The actual records on this page
        /// </summary>
        public IEnumerable<T> Items { get; set; }
        //public List<T> Items { get; set; }
    }
    public class DapperPage
    {
        public static void BuildPageQueries(long skip, long take, string sql, out string sqlCount, out string sqlPage)
        {
            // Split the SQL
            if (!PagingHelper.SplitSQL(sql, out PagingHelper.SQLParts parts))
                throw new Exception("Unable to parse SQL statement for paged query");

            sqlPage = BuildPageSql.BuildPageQuery(skip, take, parts);
            sqlCount = parts.sqlCount;
        }
    }

    static class BuildPageSql
    {
        public static string BuildPageQuery(long skip, long take, PagingHelper.SQLParts parts)
        {
            parts.sqlSelectRemoved = PagingHelper.rxOrderBy.Replace(parts.sqlSelectRemoved, "", 1);
            if (PagingHelper.rxDistinct.IsMatch(parts.sqlSelectRemoved))
            {
                parts.sqlSelectRemoved = "peta_inner.* FROM (SELECT " + parts.sqlSelectRemoved + ") peta_inner";
            }
            var sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>{2} AND peta_rn<={3}",
                                    parts.sqlOrderBy ?? "ORDER BY (SELECT NULL)", parts.sqlSelectRemoved, skip, skip + take);
            //args = args.Concat(new object[] { skip, skip + take }).ToArray();

            return sqlPage;
        }

        //SqlServer 2012及以上
        public static string BuildPageQuery2(long skip, long take, PagingHelper.SQLParts parts)
        {
            parts.sqlSelectRemoved = PagingHelper.rxOrderBy.Replace(parts.sqlSelectRemoved, "", 1);
            if (PagingHelper.rxDistinct.IsMatch(parts.sqlSelectRemoved))
            {
                parts.sqlSelectRemoved = "peta_inner.* FROM (SELECT " + parts.sqlSelectRemoved + ") peta_inner";
            }    

            var sqlOrderBy = parts.sqlOrderBy ?? "ORDER BY (SELECT NULL)";
            var sqlPage = $"SELECT {parts.sqlSelectRemoved} {sqlOrderBy} OFFSET {skip} ROWS FETCH NEXT {take} ROWS ONLY";
            return sqlPage;
        }
    }

    static class PagingHelper
    {
        public struct SQLParts
        {
            public string sql;
            public string sqlCount;
            public string sqlSelectRemoved;
            public string sqlOrderBy;
        }

        public static bool SplitSQL(string sql, out SQLParts parts)
        {
            parts.sql = sql;
            parts.sqlSelectRemoved = null;
            parts.sqlCount = null;
            parts.sqlOrderBy = null;

            // Extract the columns from "SELECT <whatever> FROM"
            var m = rxColumns.Match(sql);
            if (!m.Success)
                return false;

            // Save column list and replace with COUNT(*)
            Group g = m.Groups[1];
            parts.sqlSelectRemoved = sql.Substring(g.Index);

            if (rxDistinct.IsMatch(parts.sqlSelectRemoved))
                parts.sqlCount = sql.Substring(0, g.Index) + "COUNT(" + m.Groups[1].ToString().Trim() + ") " + sql.Substring(g.Index + g.Length);
            else
                parts.sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);


            // Look for the last "ORDER BY <whatever>" clause not part of a ROW_NUMBER expression
            m = rxOrderBy.Match(parts.sqlCount);
            if (!m.Success)
            {
                parts.sqlOrderBy = null;
            }
            else
            {
                g = m.Groups[0];
                parts.sqlOrderBy = g.ToString();
                parts.sqlCount = parts.sqlCount.Substring(0, g.Index) + parts.sqlCount.Substring(g.Index + g.Length);
            }

            return true;
        }

        public static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
        public static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?!.*?(?:\)|\s+)AS\s)(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
        public static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
    }

Para crear sentencias de paginación, los ejemplos son BuildPageQuery y BuildPageQuery2. El primero es paginar a través de ROW_NUMBER (para SqlServer 2005 y 2008) y el último es paginar a través de OFFSET y FETCH (para SqlServer 2012 y superior).Base de datos, que se puede encapsular según corresponda; 

En cuanto a la encapsulación adicional de la consulta Where, aquellos que estén interesados ​​también pueden expandirla con la consulta Dapper lamada.

Definición de unidades de trabajo y transacciones

 Ver código

Definir el almacén de datos

 Ver código

Ajuste o amplíe según sus propias necesidades, generalmente generado con la ayuda de la plantilla T4

enlace de base de datos

Lea la cadena de conexión en el archivo de configuración appsettings a través del modo Ioptions
 

public class MyDBContext : DapperDBContext
    {
        public MyDBContext(IOptions<DapperDBContextOptions> optionsAccessor) : base(optionsAccessor)
        {
        }

        protected override IDbConnection CreateConnection(string connectionString)
        {
            IDbConnection conn = new SqlConnection(connectionString);
            return conn;
        }
    }

Cuarto, uso Dapper

Startup.cs inyecta y lee la cadena de conexión de la base de datos

{
  "SQLConnString": "Data Source=(local);Initial Catalog=database;Persist Security Info=True;User ID=sa;Password=123456;MultipleActiveResultSets=True;",  
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
services.AddDapperDBContext<MyDBContext>(options =>
            {
                options.Configuration = Configuration["SQLConnString"];
            });

Ejemplo simple WebAPI o ejemplo de llamada bajo Net Core MVC:

 Ver código

 Ver código

Supongo que te gusta

Origin blog.csdn.net/weixin_55305220/article/details/122403176
Recomendado
Clasificación