内容纲要
前言
本文主要介绍在ADNC
仓储中如何撸SQL。当遇到复杂查询、多表查询、大批量写操作或者其他原因时,勉强使用EFCore原生方法去做,不一定是好的实现。
国产ORM中的优秀者SqlSugar
,FreeSql
都提供直接操作ADO执行SQL的功能,也就是说生产环境中撸SQL是避免不了的。
EFCore仓储中撸SQL
我们来看下EFCore仓储接口中与SQL有关的二个方法和一个属性,代码片段如下:
public interface IEfRepository<TEntity> : IEfBaseRepository<TEntity>
where TEntity : EfEntity
{
/// <summary>
/// 执行原生Sql查询
/// </summary>
IAdoQuerierRepository? AdoQuerier { get; }
/// <summary>
/// 执行原生Sql写操作
/// </summary>
Task<int> ExecuteSqlInterpolatedAsync(FormattableString sql, CancellationToken cancellationToken = default);
/// <summary>
/// 执行原生Sql写操作
/// </summary>
Task<int> ExecuteSqlRawAsync(string sql, CancellationToken cancellationToken = default);
}
再看下如何实现的
AdoQuerier
实现类在构造函数注入IAdoQuerierRepository接口,设置数据库连接后再赋值给该对象,ADNC中实现了该接口的只有adnc.infra.dapper工程中DapperRepository类。我们可以去看下IAdoQuerierRepository的定义,几乎包含了Dapper所有查询方法。也就是说我们在EFCore仓储中可以通过AdoQuerier属性调用Dapper所有的查询方法。ExecuteSqlInterpolatedAsync
直接调用EF原生方法DbContext.Database.ExecuteSqlInterpolatedAsync()执行Sql(写操作),该方法可以避免SQL注入的问题,尽量用该方法。-
ExecuteSqlRawAsync
直接调用EF原生方法DbContext.Database.ExecuteSqlRawAsync()执行Sql(写操作)。public sealed class EfRepository<TEntity> : AbstractEfBaseRepository<AdncDbContext, TEntity>, IEfRepository<TEntity> where TEntity : EfEntity, new() { private readonly IAdoQuerierRepository _adoQuerier; public EfRepository(AdncDbContext dbContext, IAdoQuerierRepository adoQuerier = null) : base(dbContext) => _adoQuerier = adoQuerier; public IAdoQuerierRepository AdoQuerier { get { if (_adoQuerier is null) return null; if (!_adoQuerier.HasDbConnection()) _adoQuerier.ChangeOrSetDbConnection(DbContext.Database.GetDbConnection()); return _adoQuerier; } } public async Task<int> ExecuteSqlInterpolatedAsync(FormattableString sql, CancellationToken cancellationToken = default) => await DbContext.Database.ExecuteSqlInterpolatedAsync(sql, cancellationToken); public async Task<int> ExecuteSqlRawAsync(string sql, CancellationToken cancellationToken = default) => await DbContext.Database.ExecuteSqlRawAsync(sql, cancellationToken); }
部分示例代码
var sql2 = @"SELECT * FROM Customer ORDER BY Id ASC";
var dbCustomer = await _customerRsp.AdoQuerier.QueryFirstAsync<Customer>(sql2, null, _customerRsp.CurrentDbTransaction);
var rawSql1 = "update Customer set nickname='test8888' where id=1000000000";
var rows = await _customerRsp.ExecuteSqlRawAsync(rawSql1);
var id=10000000;
var newNickName = "test8888";
FormattableString formatSql2 = $"update Customer set nickname={newNickName} where id={id}";
rows = await _customerRsp.ExecuteSqlInterpolatedAsync(formatSql2);
直接使用Dapper仓储
除非没有办法了,否则尽量不要直接使用Dapper仓储。当然直接使用Dapper仓储可以操作它支持的任意数据库,非常灵活。
public class xxxAppService
{
private IAdoExecuterWithQuerierRepository _dapperRepo;
public xxxAppService(IAdoExecuterWithQuerierRepository dapperRepo)
{
_dapperRepo = dapperRepo;
_dapperRepo.ChangeOrSetDbConnection(connectingstring,DbTypes.MYSQL);
}
public Demomethod()
{
var sql="SELECT * FROM Customer Order by Id desc";
var result = await _dapperRepo.QueryAsync(sql);
}
}
WELL DONE
全文完