FreeSql.Repository 實現了過濾器,它不只是查詢時過濾,連刪除/修改/插入時都會進行驗證,避免數據安全問題。git
目前過濾器依附在倉儲層實現,每一個倉儲實例都有 IDataFilter 屬性,可利用其完成過濾器管理,它是獨立的修改後不影響全局。github
public interface IDataFilter<TEntity> where TEntity : class { IDataFilter<TEntity> Apply(string filterName, Expression<Func<TEntity, bool>> filterAndValidateExp); IDisposable Enable(params string[] filterName); IDisposable EnableAll(); IDisposable Disable(params string[] filterName); IDisposable DisableAll(); bool IsEnabled(string filterName); }
using (repos1.DataFilter.Disable("test")) { //在這段中,repos1 之 test 過濾器失效 } //repos1 之 test 過濾器從新生效
dotnet add package FreeSql.Repositorysql
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(); public class Song { [Column(IsIdentity = true)] public int Id { get; set; } public string Title { get; set; } }
一、IFreeSql 的擴展方法;數據庫
var curd1 = fsql.GetRepository<Song, int>(); var curd2 = fsql.GetGuidRepository<Song>();
二、繼承現實;安全
public class SongRepository : BaseRepository<Song, int> { public SongRepository(IFreeSql fsql) : base(fsql) {} //在這裏增長 CURD 之外的方法 }
三、Autofac 注入,使用方法繼續往下看【全局過濾器】;ide
假設咱們有User(用戶)、Topic(主題)兩個實體,在領域類中定義了兩個倉儲:函數
var userRepository = fsql.GetGuidRepository<User>(); var topicRepository = fsql.GetGuidRepository<Topic>();
在開發過程當中,老是擔憂 topicRepository 的數據安全問題,即有可能查詢或操做到其餘用戶的主題。所以咱們在v0.0.7版本進行了改進,增長了 filter lambad 表達式參數。測試
var userRepository = fsql.GetGuidRepository<User>(a => a.Id == 1); var topicRepository = fsql.GetGuidRepository<Topic>(a => a.UserId == 1);
全局過濾器,可幫助實現「軟刪除」、「租戶」等設計,目前使用 Autofac 注入的方式實現的全局過濾器。ui
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddSingleton<IFreeSql>(fsql); services.AddMvc(); var builder = new ContainerBuilder(); //示範全局過濾的倉儲類注入,若是實體中不存在 Title 屬性,則條件不生效 builder.RegisterFreeRepository(filter => filter.Apply<Song>("test", a => a.Title == DateTime.Now.ToString() + Thread.CurrentThread.ManagedThreadId) ); builder.Populate(services); var container = builder.Build(); return new AutofacServiceProvider(container); } public class xxxx { public int Id { get; set; } } public class Song { [Column(IsIdentity = true)] public int Id { get; set; } public string Title { get; set; } } //在控制器使用 public SongsController(GuidRepository<Song> repos1, GuidRepository<xxxx> repos2) { //在此打斷點,調試 }
第一次請求:設計
repos1.Select.ToSql()
"SELECT a."Id", a."Title" \r\nFROM "Song" a \r\nWHERE (a."Title" = strftime('%Y-%m-%d %H:%M.%f',datetime(current_timestamp,'localtime')) || 21)"
repos2.Select.ToSql()
"SELECT a."Id" \r\nFROM "xxxx" a"
第二次請求:
repos1.Select.ToSql()
"SELECT a."Id", a."Title" \r\nFROM "Song" a \r\nWHERE (a."Title" = strftime('%Y-%m-%d %H:%M.%f',datetime(current_timestamp,'localtime')) || 4)"
repos2.Select.ToSql()
"SELECT a."Id" \r\nFROM "xxxx" a"
//禁用過濾器
repos1.DataFilter.Disable("test")
repos1.Select.ToSql()
"SELECT a."Id", a."Title" \r\nFROM "Song" a"
測試總結:
一、注入的變量值在使用時有了動態變化,每次獲取時都是新的(Thread.CurrentThread.ManagedThreadId);
二、設定的全局過濾,若某實體不存在表達式函數中的字段時,不會生效(如上xxxx不存在Title);
三、使用 DataFilter.Disable("test") 可臨時關閉過濾器的效果,使用 DataFilter.Enable("test") 可從新開啓;
四、倉儲對象建立時,從全局過濾器copy進來,而後本身管理本身。修改後不影響其餘或全局設置。
github 源碼: https://github.com/2881099/FreeSql