FreeSql 過濾器使用介紹

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

相關文章
相關標籤/搜索