Dapper in .Net Core
一、前言
关于什么是Dapper,在此不做赘述;本文仅对Dapper在.Net Core中的使用作扼要说明,所陈代码以示例讲解为主,乃抛砖引玉,开发者可根据自身需要进行扩展和调整;其中如有疏漏之处,望不吝斧正。
二、Dapper环境搭建
当前以.Net Core WebAPI或MVC项目为例,框架版本为.NET 5.0,相关NuGet包引用如下:
Install-Package Dapper
Install-Package Dapper.Contrib
Install-Package Dapper.SqlBuilder
Install-Package System.Data.SqlClient
其中Dapper.Contrib和Dapper.SqlBuilder为Dapper的扩展,当然,Dapper的扩展还有如Dapper.Rainbow等其他包,根据自身需要引用,对相关引用作下说明:
- Dapper:不言而喻;
- Dapper.Contrib:可使用对象进行数据表的增删改查,免却SQL语句的编写;
- Dapper.SqlBuilder:可以方便动态构建SQL语句,如Join、SELECT、Where、OrderBy等等;
- System.Data.SqlClient:由于示例数据库为Sql Server,如MySql则引用MySql.Data;
对于Dapper.Contrib实体配置选项,以Product类为例,作扼要说明如下:
[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; }
}
对于实体配置项,有如下几个主要项:
- Table:指定数据库表名,可忽略;
- Key:指定为自动增长主键;
- ExplicitKey:指定非自动增长主键,如guid;
- Computed:计算列属性,Insert、Update操作将忽略此列;
- Write:是否可写入,true/false,如[Write(false)],false时Insert、Update操作将忽略此列,比如可扩展局部类作数据表额外查询字段使用;
对于数据表对象实体,可结合T4模板生成即可。
三、Dapper封装
关于Dapper数据访问,这里参考Github上的某示例(入口:https://github.com/EloreTec/UnitOfWorkWithDapper),作修改调整封装如下:
定义DapperDBContext类


public abstract class DapperDBContext : IContext
{
private IDbConnection _connection;
private IDbTransaction _transaction;
private int? _commandTimeout = null;
private readonly DapperDBContextOptions _options; public bool IsTransactionStarted { get; private set; } protected abstract IDbConnection CreateConnection(string connectionString); protected DapperDBContext(IOptions<DapperDBContextOptions> optionsAccessor)
{
_options = optionsAccessor.Value; _connection = CreateConnection(_options.Configuration);
_connection.Open(); DebugPrint("Connection started.");
} #region Transaction public void BeginTransaction()
{
if (IsTransactionStarted)
throw new InvalidOperationException("Transaction is already started."); _transaction = _connection.BeginTransaction();
IsTransactionStarted = true; DebugPrint("Transaction started.");
} public void Commit()
{
if (!IsTransactionStarted)
throw new InvalidOperationException("No transaction started."); _transaction.Commit();
_transaction = null; IsTransactionStarted = false; DebugPrint("Transaction committed.");
} public void Rollback()
{
if (!IsTransactionStarted)
throw new InvalidOperationException("No transaction started."); _transaction.Rollback();
_transaction.Dispose();
_transaction = null; IsTransactionStarted = false; DebugPrint("Transaction rollbacked and disposed.");
} #endregion Transaction #region Dapper.Contrib.Extensions public async Task<T> GetAsync<T>(int id) where T : class, new()
{
return await _connection.GetAsync<T>(id, _transaction, _commandTimeout);
} public async Task<T> GetAsync<T>(string id) where T : class, new()
{
return await _connection.GetAsync<T>(id, _transaction, _commandTimeout);
} public async Task<IEnumerable<T>> GetAllAsync<T>() where T : class, new()
{
return await _connection.GetAllAsync<T>();
} public long Insert<T>(T model) where T : class, new()
{
return _connection.Insert<T>(model, _transaction, _commandTimeout);
} public async Task<int> InsertAsync<T>(T model) where T : class, new()
{
return await _connection.InsertAsync<T>(model, _transaction, _commandTimeout);
}
public bool Update<T>(T model) where T : class, new()
{
return _connection.Update<T>(model, _transaction, _commandTimeout);
} public async Task<bool> UpdateAsync<T>(T model) where T : class, new()
{
return await _connection.UpdateAsync<T>(model, _transaction, _commandTimeout);
} public async Task<Page<T>> PageAsync<T>(long pageIndex, long pageSize, string sql, object param = null)
{
DapperPage.BuildPageQueries((pageIndex - 1) * pageSize, pageSize, sql, out string sqlCount, out string sqlPage); var result = new Page<T>
{
CurrentPage = pageIndex,
ItemsPerPage = pageSize,
TotalItems = await _connection.ExecuteScalarAsync<long>(sqlCount, param)
};
result.TotalPages = result.TotalItems / pageSize; if ((result.TotalItems % pageSize) != 0)
result.TotalPages++; result.Items = await _connection.QueryAsync<T>(sqlPage, param);
return result;
} #endregion #region Dapper Execute & Query public int ExecuteScalar(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return _connection.ExecuteScalar<int>(sql, param, _transaction, _commandTimeout, commandType);
} public async Task<int> ExecuteScalarAsync(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return await _connection.ExecuteScalarAsync<int>(sql, param, _transaction, _commandTimeout, commandType);
}
public int Execute(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return _connection.Execute(sql, param, _transaction, _commandTimeout, commandType);
} public async Task<int> ExecuteAsync(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return await _connection.ExecuteAsync(sql, param, _transaction, _commandTimeout, commandType);
} public IEnumerable<T> Query<T>(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return _connection.Query<T>(sql, param, _transaction, true, _commandTimeout, commandType);
} public async Task<IEnumerable<T>> QueryAsync<T>(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return await _connection.QueryAsync<T>(sql, param, _transaction, _commandTimeout, commandType);
} public T QueryFirstOrDefault<T>(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return _connection.QueryFirstOrDefault<T>(sql, param, _transaction, _commandTimeout, commandType);
} public async Task<T> QueryFirstOrDefaultAsync<T>(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return await _connection.QueryFirstOrDefaultAsync<T>(sql, param, _transaction, _commandTimeout, commandType);
}
public IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(string sql, Func<TFirst, TSecond, TReturn> map, object param = null, string splitOn = "Id", CommandType commandType = CommandType.Text)
{
return _connection.Query(sql, map, param, _transaction, true, splitOn, _commandTimeout, commandType);
} public async Task<IEnumerable<TReturn>> QueryAsync<TFirst, TSecond, TReturn>(string sql, Func<TFirst, TSecond, TReturn> map, object param = null, string splitOn = "Id", CommandType commandType = CommandType.Text)
{
return await _connection.QueryAsync(sql, map, param, _transaction, true, splitOn, _commandTimeout, commandType);
} public async Task<SqlMapper.GridReader> QueryMultipleAsync(string sql, object param = null, CommandType commandType = CommandType.Text)
{
return await _connection.QueryMultipleAsync(sql, param, _transaction, _commandTimeout, commandType);
} #endregion Dapper Execute & Query public void Dispose()
{
if (IsTransactionStarted)
Rollback(); _connection.Close();
_connection.Dispose();
_connection = null; DebugPrint("Connection closed and disposed.");
} private void DebugPrint(string message)
{
#if DEBUG
Debug.Print(">>> UnitOfWorkWithDapper - Thread {0}: {1}", Thread.CurrentThread.ManagedThreadId, message);
#endif
}
}


public class DapperDBContextOptions : IOptions<DapperDBContextOptions>
{
public string Configuration { get; set; } DapperDBContextOptions IOptions<DapperDBContextOptions>.Value
{
get { return this; }
}
} public interface IContext : IDisposable
{
bool IsTransactionStarted { get; } void BeginTransaction(); void Commit(); void Rollback();
}
以上代码涵盖了Dapper访问数据库的基本操作,分同步和异步,其中大部分不作赘述,着重说下分页部分;
异步分页构建(PageAsync)
分页这里为方便调用,只需传入要查询的Sql语句(如:SELECT * FROM Table,必须带Order BY)、页索引、页大小即可;
至于具体如何构建的,这里参照某小型ORM工具PetaPoco,抽取相关代码如下,有兴趣的同学也可以自行改造:
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);
}
对于构建分页语句,分别示例BuildPageQuery和BuildPageQuery2,前者为通过ROW_NUMBER进行分页(针对SqlServer2005、2008),后者通过OFFSET、FETCH分页(针对SqlServer2012及以上版本),相关辅助操作类一览便知,如果使用MySql数据库,可酌情自行封装;
至于Where查询的进一步封装,有兴趣的也可兑Dapper lamada查询进行扩展。
定义工作单元与事务


public interface IUnitOfWork : IDisposable
{
void SaveChanges();
} public interface IUnitOfWorkFactory
{
IUnitOfWork Create();
} public class UnitOfWork : IUnitOfWork
{
private readonly IContext _context; public UnitOfWork(IContext context)
{
_context = context;
_context.BeginTransaction();
} public void SaveChanges()
{
if (!_context.IsTransactionStarted)
throw new InvalidOperationException("Transaction have already been commited or disposed."); _context.Commit();
} public void Dispose()
{
if (_context.IsTransactionStarted)
_context.Rollback();
}
} public class DapperUnitOfWorkFactory : IUnitOfWorkFactory
{
private readonly DapperDBContext _context; public DapperUnitOfWorkFactory(DapperDBContext context)
{
_context = context;
} public IUnitOfWork Create()
{
return new UnitOfWork(_context);
}
}
定义数据仓储


#region Product
public partial interface IProductRepository
{
Task<Product> GetAsync(int id); Task<IEnumerable<Product>> GetAllAsync(); long Insert(Product model); Task<int> InsertAsync(Product model); bool Update(Product model); Task<bool> UpdateAsync(Product model); int Count(string where, object param = null); Task<int> CountAsync(string where, object param = null); bool Exists(string where, object param = null); Task<bool> ExistsAsync(string where, object param = null); Product FirstOrDefault(string where, object param = null); Task<Product> FirstOrDefaultAsync(string where, object param = null); T FirstOrDefault<T>(string sql, object param = null); Task<T> FirstOrDefaultAsync<T>(string sql, object param = null); IEnumerable<Product> Fetch(SqlBuilder where); Task<IEnumerable<Product>> FetchAsync(SqlBuilder where); IEnumerable<T> Fetch<T>(string sql, SqlBuilder where, bool orderBy = true); Task<IEnumerable<T>> FetchAsync<T>(string sql, SqlBuilder where, bool orderBy = true); Task<Page<Product>> PageAsync(long pageIndex, long pageSize, SqlBuilder builder); Task<Page<T>> PageAsync<T>(string sql, long pageIndex, long pageSize, SqlBuilder builder); Task<SqlMapper.GridReader> QueryMultipleAsync(string sql, object param = null);
} public partial class ProductRepository : IProductRepository
{
private readonly DapperDBContext _context;
public ProductRepository(DapperDBContext context)
{
_context = context;
} public async Task<Product> GetAsync(int id)
{
return await _context.GetAsync<Product>(id);
} public async Task<IEnumerable<Product>> GetAllAsync()
{
return await _context.GetAllAsync<Product>();
} public long Insert(Product model)
{
return _context.Insert<Product>(model);
} public async Task<int> InsertAsync(Product model)
{
return await _context.InsertAsync<Product>(model);
} public bool Update(Product model)
{
return _context.Update<Product>(model);
} public async Task<bool> UpdateAsync(Product model)
{
return await _context.UpdateAsync<Product>(model);
} public int Count(string where, object param = null)
{
string strSql = $"SELECT COUNT(1) FROM Product {where}";
return _context.ExecuteScalar(strSql, param);
} public async Task<int> CountAsync(string where, object param = null)
{
string strSql = $"SELECT COUNT(1) FROM Product {where}";
return await _context.ExecuteScalarAsync(strSql, param);
} public bool Exists(string where, object param = null)
{
string strSql = $"SELECT TOP 1 1 FROM Product {where}";
var count = _context.ExecuteScalar(strSql, param);
return count > 0;
} public async Task<bool> ExistsAsync(string where, object param = null)
{
string strSql = $"SELECT TOP 1 1 FROM Product {where}";
var count = await _context.ExecuteScalarAsync(strSql, param);
return count > 0;
} public Product FirstOrDefault(string where, object param = null)
{
string strSql = $"SELECT TOP 1 * FROM Product {where}";
return _context.QueryFirstOrDefault<Product>(strSql, param);
} public async Task<Product> FirstOrDefaultAsync(string where, object param = null)
{
string strSql = $"SELECT TOP 1 * FROM Product {where}";
return await _context.QueryFirstOrDefaultAsync<Product>(strSql, param);
} public T FirstOrDefault<T>(string sql, object param = null)
{
return _context.QueryFirstOrDefault<T>(sql, param);
} public async Task<T> FirstOrDefaultAsync<T>(string sql, object param = null)
{
return await _context.QueryFirstOrDefaultAsync<T>(sql, param);
} public IEnumerable<Product> Fetch(SqlBuilder where)
{
var strSql = where.AddTemplate(@"SELECT * FROM Product /**where**/ /**orderby**/");
return _context.Query<Product>(strSql.RawSql, strSql.Parameters);
} public async Task<IEnumerable<Product>> FetchAsync(SqlBuilder where)
{
var strSql = where.AddTemplate(@"SELECT * FROM Product /**where**/ /**orderby**/");
return await _context.QueryAsync<Product>(strSql.RawSql, strSql.Parameters);
} public IEnumerable<T> Fetch<T>(string sql, SqlBuilder where, bool orderBy = true)
{
var _sql = orderBy ? $"{sql} /**where**/ /**orderby**/" : $"{sql} /**where**/";
var strSql = where.AddTemplate(_sql);
return _context.Query<T>(strSql.RawSql, strSql.Parameters);
} public async Task<IEnumerable<T>> FetchAsync<T>(string sql, SqlBuilder where, bool orderBy = true)
{
var _sql = orderBy ? $"{sql} /**where**/ /**orderby**/" : $"{sql} /**where**/";
var strSql = where.AddTemplate(_sql);
return await _context.QueryAsync<T>(strSql.RawSql, strSql.Parameters);
} public async Task<Page<Product>> PageAsync(long pageIndex, long pageSize, SqlBuilder builder)
{
var strSql = "SELECT * FROM Product";
return await PageAsync<Product>(strSql, pageIndex, pageSize, builder);
} public async Task<Page<T>> PageAsync<T>(string sql, long pageIndex, long pageSize, SqlBuilder builder)
{
var strSql = builder.AddTemplate($"{sql} /**where**/ /**orderby**/");
return await _context.PageAsync<T>(pageIndex, pageSize, strSql.RawSql, strSql.Parameters);
} public async Task<SqlMapper.GridReader> QueryMultipleAsync(string sql, object param = null)
{
return await _context.QueryMultipleAsync(sql, param);
}
}
#endregion
根据自身需要进行调整或扩展,一般借助T4模板生成
数据库连接
通过Ioptions模式读取配置文件appsettings中连接字符串
public class MyDBContext : DapperDBContext
{
public MyDBContext(IOptions<DapperDBContextOptions> optionsAccessor) : base(optionsAccessor)
{
} protected override IDbConnection CreateConnection(string connectionString)
{
IDbConnection conn = new SqlConnection(connectionString);
return conn;
}
}
四、Dapper使用
Startup.cs注入并读取数据库连接字符串
{
"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"];
});
简单示例WebAPI或Net Core MVC下的调用示例:


public class ProductController : BaseController
{
private readonly IProductRepository _productRepository; public ProductController(
IProductRepository productRepository )
{ _productRepository = productRepository; } //商品列表
[HttpGet]
public async Task<IActionResult> ProductList(DateTime? startDate, DateTime? endDate, int id = 1, int productStatus = 0, string keyword = "")
{
var model = new ProductModels();
var builder = new Dapper.SqlBuilder();
builder.Where("ProductStatus!=@ProductStatus", new { ProductStatus = productStatus }); if (startDate.HasValue)
{
builder.Where("CreateTime>=@startDate", new { startDate = startDate.Value});
}
if (endDate.HasValue)
{
builder.Where("CreateTime<@endDate", new { endDate = endDate.Value.AddDays(1)});
} if (!string.IsNullOrWhiteSpace(keyword))
{
builder.Where("Name LIKE @keyword", new { keyword = $"%{StringHelper.ReplaceSql(keyword)}%" });
} builder.OrderBy("SortNum DESC,CreateTime DESC"); var list = await _productRepository.PageAsync(id, PageSize, builder); model.ProductList = new PagedList<Product>(list.Items, id, PageSize, list.TotalItems); if (Request.IsAjaxRequest())
return PartialView("_ProductList", model.ProductList); return View(model);
} //添加商品
[HttpPost]
public async Task<int> AddProduct(ProductModels model)
{
return await _productRepository.InsertAsync(model);
} }


public partial interface IProductService
{
Task<bool> AddProduct(Product productInfo, List<ProductStock> skuList); }
public class ProductService: IProductService
{
private readonly DapperDBContext _context;
private readonly IUnitOfWorkFactory _uowFactory; public ProductService(DapperDBContext context, IUnitOfWorkFactory uowFactory)
{
_context = context;
_uowFactory = uowFactory;
} /// <summary>
/// 添加商品
/// </summary>
/// <param name="productInfo"></param>
/// <param name="skuList"></param>
/// <returns></returns>
public async Task<bool> AddProduct(Product productInfo, List<ProductStock> skuList)
{
var result = false;
using (var uow = _uowFactory.Create())
{
//添加产品
await _context.InsertAsync(productInfo); //添加Sku库存售价 //await _context.InsertAsync(skuList); uow.SaveChanges();
result = true;
}
return result;
} }
Dapper in .Net Core的更多相关文章
- ASP.NET Core:使用Dapper和SwaggerUI来丰富你的系统框架
一.概述 1.用VS2017创建如下图的几个.NET Standard类库,默认版本为1.4,你可以通过项目属性进行修改,最高支持到1.6,大概五月份左右会更新至2.0,API会翻倍,很期待! 排名分 ...
- 在.NetCore(C#)中使用ODP.NET Core+Dapper操作Oracle数据库
前言 虽然一直在说"去IOE化",但是在国企和政府,Oracle的历史包袱实在太重了,甚至很多业务逻辑都是写在Oracle的各种存储过程里面实现的-- 我们的系统主要的技术栈是Dj ...
- [开源ORM] SqliteSugar 3.x .net Core版本成功上线
SqliteSqlSugar 3.X API 作为支持.NET CORE 为数不多的ORM之一,除了具有优越的性能外,还拥有强大的功能,不只是满足你的增,删,查和改.实质上拥有更多你想像不到的功能,当 ...
- N[开源].NET CORE与MySql更配, MySqlSugar ORM框架 3.x
MySqlSugar 3.X API 作为支持.NET CORE 为数不多的ORM之一,除了具有优越的性能外,还拥有强大的功能,不只是满足你的增,删,查和改.实质上拥有更多你想像不到的功能,当你需要实 ...
- [翻译] 介绍EF Core
Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...
- Dapper and Repository Pattern in MVC
大家好,首先原谅我标题是英文的,因为我想不出好的中文标题. 这里我个人写了一个Dapper.net 的Repository模式的底层基础框架. 涉及内容: Dapper.net结合Repository ...
- linux 环境下部署 Asp.Net Core 项目 访问 oralce 数据库
1.ASP.NET Core 是一个跨平台的高性能开源框架,可以部署到Linux上,那项目部署在Linux上有哪些好处呢? 1.linux硬件需求小,大部分版本免费,成本低. 2.linux的用户管理 ...
- EF core 性能调优
Entity Framework Core performance tuning – a worked example Last Updated: February 25, 2019 | Create ...
- C# 数据操作系列 - 17 Dapper ——号称可以与ADO.NET 同台飙车的ORM
0. 前言 之前四篇介绍了一个国内开发者开发的优秀框架SqlSugar,给我们眼前一亮的感觉.这一篇,我们将试试另一个出镜率比较高的ORM框架-Dapper. Dapper是一个轻量级的ORM框架,其 ...
随机推荐
- CPU 是如何认识和执行代码的
CPU的介绍 CPU 也称为微处理器,是计算机的心脏和/或大脑. 深入研究计算机的核心,可以帮助我们有效地编写计算机程序. CPU 是计算机的心脏和大脑,它执行提供给他们的指令.它的主要工作是执行算术 ...
- Android权限级别(protectionLevel)
通常情况下,对于需要付费的操作以及可能涉及到用户隐私的操作,我们都会格外敏感. 出于上述考虑以及更多的安全考虑,Android中对一些访问进行了限制,如网络访问(需付费)以及获取联系人(涉及隐私)等. ...
- OkHttp3 使用
导入 compile 'com.squareup.okhttp3:okhttp:3.3.0' GET请求 String url = "https://www.baidu.com/" ...
- 【Linux】【Basis】块存储,文件存储,对象存储
1. 块存储: 定义:这种接口通常以QEMU Driver或者Kernel Module的方式存在,这种接口需要实现Linux的Block Device的接口或者QEMU提供的Block Driver ...
- 【Java基础】ArrayList初始化操作
要用60个零初始化列表,请执行以下操作: List<Integer> list = new ArrayList<Integer>(Collections.nCopies(60, ...
- 【Java 与数据库】How to Timeout JDBC Queries
How to Timeout JDBC Queries JDBC queries by default do not have any timeout, which means that a quer ...
- String 、StringBuffer、StringBuilder的区别
String:字符串常量 StringBuffer:字符串变量:线程安全的 StringBuilder:字符串变量:线程非安全的 三者执行速度比较:StringBuilder > String ...
- 【JavaScript】创建全0的Array
1.创建一个长度为m的全0数组 var arr = new Array(m).fill(0); 2.创建一个m行n列的全0数组 var arr = new Array(m).fill(new Arra ...
- MySQL安装详细教程(数据库免安装版)
MySQL安装详细教程(数据库免安装版)mysql-5.7.33-winx64.zip 一.软件下载 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产 ...
- 玩转 Mockjs,前端也能跑的很溜
mockjs作用就是,生成随机模拟数据,拦截 ajax 请求,可以对数据进行增删改查.在生成数据时,我们就需要能够熟练使用 mock.js 的语法. Mockjs 的语法规范包括两部分:数据模板定 ...