FreeSql 已支持 .NetFramework 4.0、ODBC 訪問

FreeSql 開源發佈快一年了,目前主倉庫代碼量 64118 行,用 git 命令統計的命令如下:

find . "(" -name "*.cs" ")" -print | xargs wc -l

加上其他幾個擴展包的代碼,大約有 70000 行源碼。

倉庫地址:https://github.com/2881099/FreeSql

在金九銀十的日子,發佈了兩大重要支持更新,分別是 .NetFramework4.0 和 ODBC。

隨着不斷的迭代更新,越來越穩定,也越來越強大。預計在一週年的時候(2020年1月1日)發佈 1.0 正式版本。

由於篇幅原因,太短則上不了首頁,同時也對不起觀衆,下面介紹一下最近更新的幾個較實用的功能:

ISelect.ToDelete/ToUpdate

IFreeSql 之 CRUD 方法,分別對應 IInsert、ISelect、IUpdate、IDelete。

IDelete 默認不支持導航對象,多表關聯等。ISelect.ToDelete 可將查詢對象轉爲刪除對象,以便支持導航對象或其他查詢功能刪除數據,如下:

fsql.Select<T1>().Where(a => a.Options.xxx == 1).ToDelete().ExecuteAffrows();

注意:此方法不是將數據查詢到內存循環刪除,上面的代碼產生如下 SQL 執行:

DELETE FROM `T1` WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1)

複雜刪除使用該方案的好處:

  • 刪除前可預覽測試數據,防止錯誤刪除操作,實現所查、即所刪;
  • 支持更加複雜的刪除操作(IDelete 默認只支持簡單的操作),甚至在 ISelect 上使用 Limit(10) 將只刪除附合條件的前 10條記錄;

ToUpdate 功能大概相同。

GlobalFilter 全局過濾

FreeSql 基礎層實現了 Select/Update/Delete 可設置的全局過濾器功能。

public static AsyncLocal<Guid> TenantId { get; set; } = new AsyncLocal<Guid>();

fsql.GlobalFilter
    .Apply<TestAddEnum>("test1", a => a.Id == TenantId.Value)
    .Apply<AuthorTest>("test2", a => a.Id == 111)
    .Apply<AuthorTest>("test3", a => a.Name == "11");

Apply 泛型參數可以設置爲任何類型,當使用 Select/Update/Delete 方法時會進行過濾器匹配嘗試(try catch):

  • 匹配成功的,將附加 where 條件;
  • 匹配失敗的,標記下次不再匹配,避免性能損耗;

如何禁用?

fsql.Select<TestAddEnum>().ToList(); //所有生效
fsql.Select<TestAddEnum>().DisableGlobalFilter("test1").ToList(); //禁用 test1
fsql.Select<TestAddEnum>().DisableGlobalFilter().ToList(); //禁用所有

fsql.Update/Delete 方法效果同上。

倉儲過濾器(舊功能)

這是一個原先就支持了的功能。FreeSql.Repository 也同樣實現了過濾器功能,它不僅是查詢時過濾,連刪除/修改/插入時都會進行驗證,避免數據安全問題。

注意:倉儲的過濾器與 IFreeSql.GlobalFilter 不是一個功能,可以同時生效

每個倉儲實例都有 IDataFilter 屬性,可利用其完成過濾器管理,它是獨立的修改後不影響全局。

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 (repo1.DataFilter.Disable("test")) {
    //在這段中,repo1 之 test 過濾器失效
}

//repo1 之 test 過濾器重新生效

過濾與驗證

假設我們有User(用戶)、Topic(主題)兩個實體,在領域類中定義了兩個倉儲:

var userRepository = fsql.GetGuidRepository<User>();
var topicRepository = fsql.GetGuidRepository<Topic>();

在開發過程中,總是擔心 topicRepository 的數據安全問題,即有可能查詢或操作到其他用戶的主題。因此我們在v0.0.7版本進行了改進,增加了 filter lambda 表達式參數。

var userRepository = fsql.GetGuidRepository<User>(a => a.Id == 1);
var topicRepository = fsql.GetGuidRepository<Topic>(a => a.UserId == 1);
  • 在查詢/修改/刪除時附加此條件,從而達到不會修改其他用戶的數據;
  • 在添加時,使用表達式驗證數據的合法性,若不合法則拋出異常;

實體變化通知

該功能依附在 FreeSql.Repository 上實現的,對實體的變化進行統一轉發,以便實現全局或局部類似日誌的功能。

全局設置:

fsql.SetDbContextOptions(opt => {
    opt.OnEntityChange = report => {
        Console.WriteLine(report);
    };
});

單獨設置 DbContext 或者 UnitOfWork:

var ctx = fsql.CreateDbContext();
ctx.Options.OnEntityChange = report => {
    Console.WriteLine(report);
};

var uow = fsql.CreateUnitOfWork();
uow.OnEntityChange = report => {
    Console.WriteLine(report);
};

參數 report 是一個 List 集合,集合元素的類型定義如下:

public class EntityChangeInfo
{
    public object Object { get; set; }
    public EntityChangeType Type { get; set; }
}
public enum EntityChangeType { Insert, Update, Delete, SqlRaw }
變化類型- 說明
Insert 實體對象被插入
Update 實體對象被更新
Delete 實體對象被刪除
SqlRaw 執行了SQL語句

SqlRaw 目前有兩處地方比較特殊:

  • 多對多聯級更新導航屬性的時候,對中間表的全部刪除操作;
  • 通用倉儲類 BaseRepository 有一個 Delete 方法,參數爲表達式,而並非實體;
int Delete(Expression<Func<TEntity, bool>> predicate);

DbContext.SaveChanges,或者 Repository 對實體的 Insert/Update/Delete,或者 UnitOfWork.Commit 操作都會最多觸發一次該事件。

更多功能

請移步更新日誌:https://github.com/2881099/FreeSql/wiki/%e6%9b%b4%e6%96%b0%e6%97%a5%e5%bf%97

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章