FreeSql v0.11いくつかの実用的な機能の説明

9385 ワード

FreeSqlのオープンソースが発表されてもうすぐ1年になります.Netプラットフォームの便利で使いやすいORM、倉庫の住所:https://github.com/2881099/FreeSql
反復的な更新に伴い、ますます安定し、ますます強くなります.1周年(2020年1月1日)に1.0本リリース予定.
金九銀十の日が過ぎて、この銅の普通の月の中で、私はいくつかの重大な機能をして、使用者の開発にもっと大きな便利さを提供することを望んでいます.
  • 一、Dtoマッピングクエリ
  • 二、IncludeManyカスケードロード
  • 三、Where(a=>true)論理式解析最適化
  • 四、SaveManyToMany連番保存多対多集合属性
  • 5、エンティティの移行-指定したテーブル名
  • 六、MySql特有機能On Duplicate Key Update、Pgsql upsert
  • 7、ISelect.ToDelete高度削除
  • 8、グローバルフィルタ
  • 次のコードです.前提定義コードは次のとおりです.
    IFreeSql fsql = new FreeSql.FreeSqlBuilder()
        .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\db1.db;Max Pool Size=10";)
        .UseAutoSyncStructure(true) //            
        .Build();
    
    public class Blog
    {
        public Guid Id { get; set; }
        public string Url { get; set; }
        public int Rating { get; set; }
    }

    一、Dtoマッピングクエリー

    class Dto
    {
        public Guid Id { get; set; }
        public string Url { get; set; }
        public int xxx { get; set; }
    }
    
    fsql.Select().ToList();
    //SELECT Id, Url FROM Blog
    
    fsql.Select().ToList(a => new Dto { xxx = a.Rating} );
    //SELECT Id, Url, Rating as xxx FROM Blog
    //   ,      ,      xxx
    
    fsql.Select().ToList(a => new Blog { Id = a.Id }) 
    //   ,    id
    
    fsql.Select().ToList(a => new { a.Id }) 
    //   ,    id,      

    マッピングは単一テーブル/マルチテーブルをサポートし、データをクエリーする前にマッピングされます(すべてのフィールドをクエリーしてからメモリにマッピングするわけではありません).
    ルールの検索、属性名の検索、内部オブジェクトのループtables(joinクエリ後に増加)は、同じフィールドが検出されるまでプライマリ・テーブルで優先的に調べます.
    次のようになります.
    A,B,Cともにid,Dto{id,a 1,a 2,b 1,b 2},A.idがマッピングされる.id=C.idマッピングを指定することもできます.
    友情の注意:dtoでナビゲーション属性を直接マッピングできます

    二、IncludeManyカスケードロード


    以前は実装されていましたが、リレーションシップの設定、およびリレーションシップの設定されていないナビゲーションセットのプロパティがカスケード・ロードされています.
    関係を設定する(一対多、多対多をサポート):
    fsql.Select().IncludeMany(a => a.Goods).ToList();

    関係が設定されていない場合は、一時的に関係を指定します(1対以上しかサポートされていません):
    fsql.Select().IncludeMany(a => a.Comment.Where(b => b.TagId == a.Id));

    EfCoreのようにすべてのデータをロードしてIOのパフォーマンスが低下しないように、各サブセットの最初の数のデータのみをクエリーします(たとえば、ある商品の下に2000件のコメントがあります):
    fsql.Select().IncludeMany(a => a.Comment.Take(10));

    上記のIncludeMany機能は、まだ自由で柔軟ではありません.

    新機能1:DtoにマッピングするIncludeMany


    古いIncludeMany制限はISelect内でしか使用できません.まず上位データを調べなければなりません.この問題を解決するには、Dto上で直接マッピングしました.
    Goods商品表を検索して、分類1、分類2、分類3各10個のデータ
    //     ,     Dto  
    class Dto {
        public int TypeId { get; set; }
        public List GoodsList { get; set; }
    }
    
    var dto = new [] { 1,2,3 }.Select(a => new Dto { TypeId = a }).ToList();
    dto.IncludeMany(d => d.GoodsList.Take(10).Where(gd => gd.TypeId == d.TypeId));
    
    //   ,dto     .Vods     10   

    現在、IncludeManyはISelectの特許ではなく、通常のListでもデータを貪欲にロードし、内部の各要素に正確に埋め込むことができます.

    新機能2:サブセットテーブルの指定フィールドをクエリーする


    古いIncludeMany制限はサブテーブルのすべてのフィールドしか調べられず、サブテーブルが多すぎるとIO性能が浪費されます.
    新しい機能では、サブセットが一部のフィールドを返すように設定し、サブセットフィールドが多すぎるという問題を回避できます.
    fsql.Select().IncludeMany(a => a.Goods.Select(b => new Goods { Id = b.Id, Title = b.Title }));
    //    goods   id, title   ,    

    三、Where(a=>true)論理式解析最適化


    多くのORM解析式ではこの問題を処理できないと信じています.私たちは99%解決しました.
    今月はまだ罪が残っていることが発見され、問題が発見されたらすぐに解決し、ユニットテストコードを増やして後患を絶った.

    四、SaveManyToMany連番保存多対多集合属性


    その前にFreeSql.DbContextと倉庫の実装は、次のように、カスケード保存機能を実現しています.
    カスケード保存機能は、オブジェクトの保存が可能な場合、その「OneToMany」、「ManyToMany」ナビゲーション属性セットも一括保存します.
    グローバルクローズ:
    fsql.SetDbContextOptions(opt => opt.EnableAddOrUpdateNavigateList = false);

    ローカルオフ:
    var repo = fsql.GetRepository();
    repo.DbContextOptions.EnableAddOrUpdateNavigateList = false;

    新しい機能:


    エンティティの指定した「複数対複数」ナビゲーション属性を保存し、SaveManyToManyメソッドはBaseRepository、DbContextで実装されます.
    問題解決:エンティティ・クラスのナビゲーション・データが複雑すぎる場合は、カスケード保存を閉じる機能を選択するのが賢明ですが、この場合、「複数対複数」データ保存機能は、既存のデータと比較して保存するため、書くのが面倒です.
    var song = new Song { Id = 1 };
    song.Tags = new List();
    song.Tags.Add(new Tag ...);
    song.Tags.Add(new Tag ...);
    song.Tags.Add(new Tag ...);
    repo.SaveManyToMany(song, "Tags");
    //     song   tag     

    メカニズム・ルールは、カスケードで保存されている「複数対複数」と同様に、次のようになります.
    中間テーブルの保存は完全な比較操作であり、外部エンティティの操作は新規のみです(更新しないことに注意してください).
  • プロパティセットが空の場合、関連するすべてのデータ(中間テーブル)
  • を削除します.
  • 属性集合が空でない場合、データベースに存在する関連データ(中間テーブル)と完全に対比し、削除および追加すべきレコード
  • を算出する.

    五、エンティティの移行-指定したテーブル名へ

    fsql.CodeFirst.SyncStructure(typeof(Log), "Log_1"); //    Log_1  
    fsql.CodeFirst.SyncStructure(typeof(Log), "Log_2"); //    Log_2  

    この機能では、サブテーブル機能を少しアップグレードしました.以下の動作は移行動作を行います.
    fsql.Select().AsTable((_, oldname) => $"{oldname}_1");
    fsql.GetRepository(null, oldname => $"{oldname}_1");

    六、MySql特有機能On Duplicate Key UpdateとPgsql upsert


    FreeSqlは、複数の挿入または更新方法を提供する、v 0.11以前は主にFreeSqlを用いる.Repository/FreeSql.DbContextライブラリが提供するメソッド実装.
    FreeSql.RepositoryのInsertOrUpdate
    この方法はFreeSql.DbContext AddOrUpdateメソッドの機能は同じです.
    var repo = fsql.GetRepository();
    repo.InsertOrUpdate(  );

    内部のステータス管理にデータがある場合は、更新します.
    内部のステータス管理にデータが存在しない場合は、データベースが存在するかどうかをクエリーします.
    存在する場合は更新、存在しない場合は挿入
    欠点:一括操作はサポートされていない

    新機能:MySql特有機能On Duplicate Key Update


    FreeSql.Provider.MySqlとFreeSql.Provider.MySqlConnectorはv 0にあります.11.11版はMySql特有の機能、On Duplicate Key Updateをサポートしています.
    この機能は、データの挿入または更新を実現し、一括操作をサポートすることもできます.
    class TestOnDuplicateKeyUpdateInfo
    {
        [Column(IsIdentity = true)]
        public int id { get; set; }
        public string title { get; set; }
        public DateTime time { get; set; }
    }
    
    var item = new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") };
    fsql.Insert(item)
        .NoneParameter()
        .OnDuplicateKeyUpdate().ToSql();
    //INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(100, 'title-100', '2000-01-01 00:00:00.000')
    //ON DUPLICATE KEY UPDATE
    //`title` = VALUES(`title`), 
    //`time` = VALUES(`time`)

    OnDuplicateKeyUpdate()の後に呼び出せるメソッド:
    メソッド名
    説明
    IgnoreColumns
    更新カラム、メカニズム、IUpdateを無視します.IgnoreColumnsのように
    UpdateColumns
    更新カラム、メカニズム、IUpdateを指定します.UpdateColumns同様
    Set
    更新する列を手動で指定し、IUpdate.Set機能同様
    SetRaw
    Setメソッドの補足として、SQL文字列を入力できます.
    ToSql
    実行するSQL文を返します
    ExecuteAffrows
    実行、影響するローの数を返します.
    IInsertとOnDuplicateKeyUpdateには、いずれもIgnoreColumns、UpdateColumnsメソッドがあります.
    エンティティ/コレクションエンティティを挿入すると、time列は無視され、コードは次のとおりです.
    fsql.Insert(item)
        .IgnoreColumns(a => a.time)
        .NoneParameter()
        .OnDuplicateKeyUpdate().ToSql();
    //INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200')
    //ON DUPLICATE KEY UPDATE
    //`title` = VALUES(`title`), 
    //`time` = '2000-01-01 00:00:00.000'

    UPDATE time部分はVALuES(`time`)ではなく定数となり,機構は以下の通りであることが分かった.
    Insertセクションに存在するカラムはupdateでVALES(`フィールド`)として設定されます.
    Insertセクションに存在しないカラムはupdateで定数形式で設定され、エンティティ配列を操作するとcase when...end実行(IUpdateと同様);

    新機能2:PostgreSQL特有機能On Conflict Do Update


    使用方法MySql OnDuplicateKeyUpdateはほぼ同じです.

    七、ISelect.ToDeleteの高度な削除


    デフォルトのIDeleteでは、ナビゲーションオブジェクト、マルチテーブル関連付けなどはサポートされていません.ISelect.ToDeleteは、次のように、ナビゲーション・オブジェクトまたは他のクエリー機能をサポートするために、クエリーを削除オブジェクトに変更できます.
    fsql.Select().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レコードのみが削除されます.

  • そしてISelect.ToUpdate高度なデータ更新機能、使用方法類似

    八、グローバルフィルタ


    FreeSqlベース層は、Select/Update/Deleteが設定可能なグローバルフィルタ機能を実現しています.
    public static AsyncLocal TenantId { get; set; } = new AsyncLocal();
    
    fsql.GlobalFilter
        .Apply("test1", a => a.Id == TenantId.Value)
        .Apply("test2", a => a.Id == 111)
        .Apply("test3", a => a.Name == "11");

    Apply汎用パラメータは、Select/Update/Deleteメソッドを使用する場合にフィルタマッチング試行(try catch)を行う任意のタイプに設定できます.
  • マッチングに成功した場合、where条件が付加される.
  • マッチングに失敗した場合、マークは次回マッチングしなくなり、性能損失を避ける.

  • 無効にする方法
    fsql.Select().ToList(); //    
    fsql.Select().DisableGlobalFilter("test1").ToList(); //   test1
    fsql.Select().DisableGlobalFilter().ToList(); //    

    fsql.Update/Deleteメソッドの効果は同じです.
    注意:IrreeSql.GlobalFilterと倉庫フィルタは機能ではなく、同時に有効になります.

    に感謝


    バグをフィードバックしてくれた友達に感謝します!
    倉庫住所:https://github.com/2881099/FreeSql
    更新ログを移動してください:https://github.com/2881099/Fr...