FreeSqlナビゲーション属性のカスケード保存機能
12705 ワード
前に書く
FreeSql一款Netプラットフォームの下でサポートする.net framework 4.5+、.Netcore 2.1+のオープンソースORM.ユニットテストは3100+を超え、新しい開発者を引きつけ続け、生命は絶えず開発されている.
EFCoreと同様に、ナビゲーションオブジェクトもあり、「OneToOne」(一対一)、「ManyToOne」(多対一)、「OneToMany」(一対多)、「ParentChild」(親子)、「ManyToMany」(多対多)をサポートしており、エンティティ間の関連付けの構成や手動構成を約束したり、fluent apiを使用して関連付けを設定したりすることができます.
カスケード保存機能でオブジェクトの保存が可能な場合は、その「OneToMany」、「ManyToMany」ナビゲーション属性のセットも一括保存します.
メカニズム規則
[1対多]モデルでは、保存時にエンティティの属性セットをカスケードして保存できます.セキュリティの使用を考慮して、完全な比較は行われず、エンティティ属性セットの追加または更新操作のみが実現されるため、エンティティ属性セットのデータは削除されません.
完全なコントラスト機能は危険すぎるので、次のシーンを考えてみましょう.
【マルチペアマルチ】モデルでは、中間テーブルの保存は完全な比較操作であり、外部エンティティの操作は新規のみとなります(更新しないことに注意してください).
機能オン/オフ
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, "Data Source=|DataDirectory|/document22.db;Pooling=true;Max Pool Size=10")
.UseAutoSyncStructure(true) //
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText)) // SQL ,
.Build();
FreeSqlBuilderを使用して作成したIrreeSqlオブジェクト、カスケード保存機能は、デフォルトではオンです.
グローバルクローズ:
fsql.SetDbContextOptions(opt => opt.EnableAddOrUpdateNavigateList = false);
ローカルオフ:
var repo = fsql.GetRepository();
repo.DbContextOptions.EnableAddOrUpdateNavigateList = false;
1対のマルチ(OneToMany)コードテスト
展示しやすいように、以下はParentChild関係ですが、実は彼もOneToManyで、自分が自分を指しているだけです.
[Table(Name = "EAUNL_OTMP_CT")]
class CagetoryParent
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid ParentId { get; set; }
[Navigate("ParentId")]
public List Childs { get; set; }
}
テストデータの初期化:
var cts = new[] {
new CagetoryParent
{
Name = " 1",
Childs = new List(new[]
{
new CagetoryParent { Name = " 1_1" },
new CagetoryParent { Name = " 1_2" },
new CagetoryParent { Name = " 1_3" }
})
},
new CagetoryParent
{
Name = " 2",
Childs = new List(new[]
{
new CagetoryParent { Name = " 2_1" },
new CagetoryParent { Name = " 2_2" }
})
}
};
1、一括挿入を実行する:
var repo = g.sqlite.GetRepository();
repo.Insert(cts);
このメソッドを最初に実行すると、データベース・テーブルの自動作成操作が実行されます.テーブルが既に存在する場合は、比較を実行し、変更がなければ操作を実行しません.
ブレークポイントデバッグにより、出力SQLの内容がコンソールに表示されます.
INSERT INTO "EAUNL_OTMP_CT"("Id", "Name", "ParentId") VALUES('5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f', ' 1', '00000000-0000-0000-0000-000000000000'), ('5d90afcb-ed57-f6f4-0082-cb6c5b531b3e', ' 2', '00000000-0000-0000-0000-000000000000')
INSERT INTO "EAUNL_OTMP_CT"("Id", "Name", "ParentId") VALUES('5d90afcb-ed57-f6f4-0082-cb6d0c1c5f1a', ' 1_1', '5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f'), ('5d90afcb-ed57-f6f4-0082-cb6e74bd8eef', ' 1_2', '5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f'), ('5d90afcb-ed57-f6f4-0082-cb6f6267cc5f', ' 1_3', '5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f'), ('5d90afcb-ed57-f6f4-0082-cb7057c41d46', ' 2_1', '5d90afcb-ed57-f6f4-0082-cb6c5b531b3e'), ('5d90afcb-ed57-f6f4-0082-cb7156e0375e', ' 2_2', '5d90afcb-ed57-f6f4-0082-cb6c5b531b3e')
2、テストロット修正:
cts[0].Name = " 11";
cts[0].Childs.Clear();
cts[1].Name = " 22";
cts[1].Childs.Clear();
repo.Update(cts);
コンソールに出力SQLが表示されます.
UPDATE "EAUNL_OTMP_CT" SET "Name" = CASE "Id"
WHEN '5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f' THEN ' 11'
WHEN '5d90afcb-ed57-f6f4-0082-cb6c5b531b3e' THEN ' 22' END
WHERE ("Id" IN ('5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f','5d90afcb-ed57-f6f4-0082-cb6c5b531b3e'))
Childs.Clearは実行しましたが、コンソールはサブセット削除文を出力していません.完全な比較が行われていないことを示しています.
3、サブセット表にすでにデータが存在し、引き続きデータを追加する
cts[0].Name = " 111";
cts[0].Childs.Clear();
cts[0].Childs.Add(new CagetoryParent { Name = " 1_33" });
cts[1].Name = " 222";
cts[1].Childs.Clear();
cts[1].Childs.Add(new CagetoryParent { Name = " 2_22" });
repo.Update(cts);
コンソールに出力SQLが表示されます.
UPDATE "EAUNL_OTMP_CT" SET "Name" = CASE "Id"
WHEN '5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f' THEN ' 111'
WHEN '5d90afcb-ed57-f6f4-0082-cb6c5b531b3e' THEN ' 222' END
WHERE ("Id" IN ('5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f','5d90afcb-ed57-f6f4-0082-cb6c5b531b3e'))
INSERT INTO "EAUNL_OTMP_CT"("Id", "Name", "ParentId") VALUES('5d90afe8-ed57-f6f4-0082-cb725df546ea', ' 1_33', '5d90afcb-ed57-f6f4-0082-cb6b78eaaf9f'), ('5d90afe8-ed57-f6f4-0082-cb7338a6214c', ' 2_22', '5d90afcb-ed57-f6f4-0082-cb6c5b531b3e')
もう一度「一対多」(OneToMany)が完全な対比を行わず、追加または更新するだけで、テストデータを追加するときに多くのコードを簡略化できることを検証しました.
マルチペアマルチ(ManyToMany)コードテスト
以下では3つのクラスを作成し,Songはボリュームクラス,Tagは外部クラス,SongTagは中間関連データクラスとし,命名規則を用いてナビゲーション関係設定を行った.
[Table(Name = "EAUNL_MTM_SONG")]
class Song
{
public Guid Id { get; set; }
public string Name { get; set; }
public List Tags { get; set; }
}
[Table(Name = "EAUNL_MTM_TAG")]
class Tag
{
public Guid Id { get; set; }
public string TagName { get; set; }
public List Songs { get; set; }
}
[Table(Name = "EAUNL_MTM_SONGTAG")]
class SongTag
{
public Guid SongId { get; set; }
public Song Song { get; set; }
public Guid TagId { get; set; }
public Tag Tag { get; set; }
}
テストデータの初期化:
var tags = new[] {
new Tag { TagName = " " },
new Tag { TagName = "80 " },
new Tag { TagName = "00 " },
new Tag { TagName = " " }
};
var ss = new[]
{
new Song
{
Name = " .mp3",
Tags = new List(new[]
{
tags[0], tags[1]
})
},
new Song
{
Name = " .mp3",
Tags = new List(new[]
{
tags[0], tags[2]
})
}
};
1、一括挿入を実行する:
var repo = g.sqlite.GetRepository();
repo.Insert(ss);
このメソッドを最初に実行すると、データベース・テーブルの自動作成操作が実行されます.テーブルが既に存在する場合は、比較を実行し、変更がなければ操作を実行しません.
ブレークポイントデバッグにより、出力SQLの内容がコンソールに表示されます.
INSERT INTO "EAUNL_MTM_SONG"("Id", "Name") VALUES('5d90fdb3-6a6b-2c58-00c8-37974177440d', ' .mp3'), ('5d90fdb3-6a6b-2c58-00c8-37987f29b197', ' .mp3')
INSERT INTO "EAUNL_MTM_TAG"("Id", "TagName") VALUES('5d90fdb7-6a6b-2c58-00c8-37991ead4f05', ' '), ('5d90fdbd-6a6b-2c58-00c8-379a0432a09c', '80 ')
INSERT INTO "EAUNL_MTM_SONGTAG"("SongId", "TagId") VALUES('5d90fdb3-6a6b-2c58-00c8-37974177440d', '5d90fdb7-6a6b-2c58-00c8-37991ead4f05'), ('5d90fdb3-6a6b-2c58-00c8-37974177440d', '5d90fdbd-6a6b-2c58-00c8-379a0432a09c')
INSERT INTO "EAUNL_MTM_TAG"("Id", "TagName") VALUES('5d90fdcc-6a6b-2c58-00c8-379b5af59d25', '00 ')
INSERT INTO "EAUNL_MTM_SONGTAG"("SongId", "TagId") VALUES('5d90fdb3-6a6b-2c58-00c8-37987f29b197', '5d90fdb7-6a6b-2c58-00c8-37991ead4f05'), ('5d90fdb3-6a6b-2c58-00c8-37987f29b197', '5d90fdcc-6a6b-2c58-00c8-379b5af59d25')
2、ロット更新をテストし、中間表データが変化した
ss[0].Name = " .mp5";
ss[0].Tags.Clear();
ss[0].Tags.Add(tags[0]);
ss[1].Name = " .mp5";
ss[1].Tags.Clear();
ss[1].Tags.Add(tags[3]);
repo.Update(ss);
コンソールに出力SQLが表示されます.
UPDATE "EAUNL_MTM_SONG" SET "Name" = CASE "Id"
WHEN '5d90fdb3-6a6b-2c58-00c8-37974177440d' THEN ' .mp5'
WHEN '5d90fdb3-6a6b-2c58-00c8-37987f29b197' THEN ' .mp5' END
WHERE ("Id" IN ('5d90fdb3-6a6b-2c58-00c8-37974177440d','5d90fdb3-6a6b-2c58-00c8-37987f29b197'))
SELECT a."SongId", a."TagId"
FROM "EAUNL_MTM_SONGTAG" a
WHERE (a."SongId" = '5d90fdb3-6a6b-2c58-00c8-37974177440d')
DELETE FROM "EAUNL_MTM_SONGTAG" WHERE ("SongId" = '5d90fdb3-6a6b-2c58-00c8-37974177440d' AND "TagId" = '5d90fdbd-6a6b-2c58-00c8-379a0432a09c')
INSERT INTO "EAUNL_MTM_TAG"("Id", "TagName") VALUES('5d90febd-6a6b-2c58-00c8-379c21acfc72', ' ')
SELECT a."SongId", a."TagId"
FROM "EAUNL_MTM_SONGTAG" a
WHERE (a."SongId" = '5d90fdb3-6a6b-2c58-00c8-37987f29b197')
DELETE FROM "EAUNL_MTM_SONGTAG" WHERE ("SongId" = '5d90fdb3-6a6b-2c58-00c8-37987f29b197' AND "TagId" = '5d90fdb7-6a6b-2c58-00c8-37991ead4f05' OR "SongId" = '5d90fdb3-6a6b-2c58-00c8-37987f29b197' AND "TagId" = '5d90fdcc-6a6b-2c58-00c8-379b5af59d25')
INSERT INTO "EAUNL_MTM_SONGTAG"("SongId", "TagId") VALUES('5d90fdb3-6a6b-2c58-00c8-37987f29b197', '5d90febd-6a6b-2c58-00c8-379c21acfc72')
次のように処理されます.
3、関連データのクリアテスト
ss[0].Name = " .mp4";
ss[0].Tags.Clear();
ss[1].Name = " .mp4";
ss[1].Tags.Clear();
repo.Update(ss);
コンソールに出力SQLが表示されます.
DELETE FROM "EAUNL_MTM_SONGTAG" WHERE ("SongId" = '5d90fdb3-6a6b-2c58-00c8-37974177440d')
DELETE FROM "EAUNL_MTM_SONGTAG" WHERE ("SongId" = '5d90fdb3-6a6b-2c58-00c8-37987f29b197')
UPDATE "EAUNL_MTM_SONG" SET "Name" = CASE "Id"
WHEN '5d90fdb3-6a6b-2c58-00c8-37974177440d' THEN ' .mp4'
WHEN '5d90fdb3-6a6b-2c58-00c8-37987f29b197' THEN ' .mp4' END
WHERE ("Id" IN ('5d90fdb3-6a6b-2c58-00c8-37974177440d','5d90fdb3-6a6b-2c58-00c8-37987f29b197'))
「ManyToMany」(マルチペアマルチ)モデルの下で、中間テーブルは完全な対比操作であり、外部テーブルは挿入され、更新されないことをもう一度証明します.
オブジェクトのナビゲーション
カスケード保存機能に加えて、ナビゲーションオブジェクトの主な設計目的は、lambda式のクエリー操作を実行するために、エンティティ間のポイントをすばやく挿入することです.
ナビゲーション関係をカスタマイズする方法
// ,OneToMany
[Navigate("song_id")]
public virtual List Obj_song_tag { get; set; }
// ,ManyToOne/OneToOne
[Navigate("song_id")]
public virtual Song Obj_song { get; set; }
// ,ManyToMany
[Navigate(ManyToMany = typeof(tag_song))]
public virtual List tags { get; set; }
FluentApiを使用して、外部でナビゲーション関係を設定することもできます.
fsql.CodeFirst.ConfigEntity(a => a
.Navigate(b => b.roles, null, typeof( ))
.Navigate(b => b.users, "uid")
);
優先度、プロパティ>FluentApi
最後に書く
FreeSqlがリリースされてから10ヶ月が経ち、元旦には1.0の正式版がリリースされ、将来的には.Netコミュニティの下で力を与える車輪も、私が十数年も無駄にしないのではないでしょうか.Netは捨てない少しの貢献でしょう.
FreeSqlがますます良くなることを望んでいます.
原Netcoreはますます良くなりました!(3.0のアップグレードで多くの人が車をひっくり返したが、心の中にはその気持ちがあり、車をひっくり返したのはせいぜい悪口を言っただけで、悪口を言ったら続けなければならない)