前言
好多年前,DAL 作為數據庫訪問層,其實是非常流行的命名方式。
不知道從什么時候開始,倉儲層成了新的時尚名詞。目前了解到,許多人只要在項目中看見 DAL 就會覺得很 low,但是比較可笑的一點是,多數的倉儲層與 DAL 實質在做同樣的事情。
本文正要介紹這種比較 low 的方式,來現實通用的倉儲層。
參考規范
與其他規范標准一樣,倉儲層也有相應的規范定義。FreeSql.Repository 參考 abp vnext 代碼,定義和實現基礎的倉儲層(CURD),應該算比較通用的方法吧。
IBasicRepository.cs 增刪改接口
using System.Threading.Tasks;
namespace FreeSql {
public interface IBasicRepository<TEntity> : IReadOnlyRepository<TEntity>
where TEntity : class {
TEntity Insert(TEntity entity);
Task<TEntity> InsertAsync(TEntity entity);
void Update(TEntity entity);
Task UpdateAsync(TEntity entity);
IUpdate<TEntity> UpdateDiy { get; }
void Delete(TEntity entity);
Task DeleteAsync(TEntity entity);
}
public interface IBasicRepository<TEntity, TKey> : IBasicRepository<TEntity>, IReadOnlyRepository<TEntity, TKey>
where TEntity : class {
void Delete(TKey id);
Task DeleteAsync(TKey id);
}
}
IReadOnlyRepository.cs 查詢接口
using System.Threading.Tasks;
namespace FreeSql {
public interface IReadOnlyRepository<TEntity> : IRepository
where TEntity : class {
ISelect<TEntity> Select { get; }
}
public interface IReadOnlyRepository<TEntity, TKey> : IReadOnlyRepository<TEntity>
where TEntity : class {
TEntity Get(TKey id);
Task<TEntity> GetAsync(TKey id);
TEntity Find(TKey id);
Task<TEntity> FindAsync(TKey id);
}
}
IRepository.cs 倉儲接口
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace FreeSql {
public interface IRepository {
//預留
}
public interface IRepository<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity>
where TEntity : class {
void Delete(Expression<Func<TEntity, bool>> predicate);
Task DeleteAsync(Expression<Func<TEntity, bool>> predicate);
}
public interface IRepository<TEntity, TKey> : IRepository<TEntity>, IReadOnlyRepository<TEntity, TKey>, IBasicRepository<TEntity, TKey>
where TEntity : class {
}
}
現實 BaseRepository.cs 通用的倉儲基類
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace FreeSql {
public abstract class BaseRepository<TEntity> : IRepository<TEntity>
where TEntity : class {
protected IFreeSql _fsql;
public BaseRepository(IFreeSql fsql) : base() {
_fsql = fsql;
if (_fsql == null) throw new NullReferenceException("fsql 參數不可為空");
}
public ISelect<TEntity> Select => _fsql.Select<TEntity>();
public IUpdate<TEntity> UpdateDiy => _fsql.Update<TEntity>();
public void Delete(Expression<Func<TEntity, bool>> predicate) => _fsql.Delete<TEntity>().Where(predicate).ExecuteAffrows();
public void Delete(TEntity entity) => _fsql.Delete<TEntity>(entity).ExecuteAffrows();
public Task DeleteAsync(Expression<Func<TEntity, bool>> predicate) => _fsql.Delete<TEntity>().Where(predicate).ExecuteAffrowsAsync();
public Task DeleteAsync(TEntity entity) => _fsql.Delete<TEntity>(entity).ExecuteAffrowsAsync();
public TEntity Insert(TEntity entity) => _fsql.Insert<TEntity>().AppendData(entity).ExecuteInserted().FirstOrDefault();
async public Task<TEntity> InsertAsync(TEntity entity) => (await _fsql.Insert<TEntity>().AppendData(entity).ExecuteInsertedAsync()).FirstOrDefault();
public void Update(TEntity entity) => _fsql.Update<TEntity>().SetSource(entity).ExecuteAffrows();
public Task UpdateAsync(TEntity entity) => _fsql.Update<TEntity>().SetSource(entity).ExecuteAffrowsAsync();
}
public abstract class BaseRepository<TEntity, TKey> : BaseRepository<TEntity>, IRepository<TEntity, TKey>
where TEntity : class {
public BaseRepository(IFreeSql fsql) : base(fsql) {
}
public void Delete(TKey id) => _fsql.Delete<TEntity>(id).ExecuteAffrows();
public Task DeleteAsync(TKey id) => _fsql.Delete<TEntity>(id).ExecuteAffrowsAsync();
public TEntity Find(TKey id) => _fsql.Select<TEntity>(id).ToOne();
public Task<TEntity> FindAsync(TKey id) => _fsql.Select<TEntity>(id).ToOneAsync();
public TEntity Get(TKey id) => Find(id);
public Task<TEntity> GetAsync(TKey id) => FindAsync(id);
}
}
如何使用?
1、安裝
dotnet add package FreeSql.Repository
2、聲明 FreeSql,為單例
var fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
.UseLogger(loggerFactory.CreateLogger<IFreeSql>())
.UseAutoSyncStructure(true) //自動遷移實體的結構到數據庫
.Build();
ps: FreeSql 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite。
3、創建實體
public class Song {
[Column(IsIdentity = true)]
public int Id { get; set; }
public string Title { get; set; }
}
4、創建倉儲層
public class SongRepository : BaseRepository<Song, int> {
public SongRepository(IFreeSql fsql) : base(fsql) {
}
}
解釋:<Song, int> 泛值第一個參數Song是實體類型,第二個參數int為主鍵類型
至此,通過繼承 BaseRepository 非常方便的實現了倉儲層 SongRepository,他包含比較標准的 CURD 現實。
參考資料:https://github.com/2881099/FreeSql/wiki/Repository
結束語
FreeSql.Repository 的版本號目前與 FreeSql 同步更新,查看更新說明;
FreeSql 特性
- CodeFirst 遷移。
- DbFirst 從數據庫導入實體類,支持三種模板生成器。
- 采用 ExpressionTree 高性能讀取數據。
- 類型映射深入支持,比如pgsql的數組類型,匠心制作。
- 支持豐富的表達式函數。
- 支持導航屬性查詢,和延時加載。
- 支持同步/異步數據庫操作方法,豐富多彩的鏈式查詢方法。
- 支持事務。
- 支持多種數據庫,MySql/SqlServer/PostgreSQL/Oracle/Sqlite。