From 88d7985d92d71af3f2bb85eac55f306cf52a38d4 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Mon, 2 May 2022 15:01:52 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20IDelete.ToSqlCascade?= =?UTF-8?q?=20=E9=80=92=E5=BD=92=E5=88=A0=E9=99=A4=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.DbContext/FreeSql.DbContext.xml | 9 -- .../Sqlite/Curd/SqliteDeleteTest.cs | 122 ++++++++++++++++++ .../Sqlite/Curd/SqliteSelectTest.cs | 7 + FreeSql/Extensions/FreeSqlGlobalExtensions.cs | 46 ++++++- 4 files changed, 170 insertions(+), 14 deletions(-) diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index bdd16ff9..da7ace6b 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -538,14 +538,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteDeleteTest.cs b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteDeleteTest.cs index dad8da8b..f2e80606 100644 --- a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteDeleteTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteDeleteTest.cs @@ -1,7 +1,12 @@ +using FreeSql; using FreeSql.DataAnnotations; +using FreeSql.Internal.CommonProvider; +using FreeSql.Internal.Model; using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; +using System.Text; using Xunit; namespace FreeSql.Tests.Sqlite @@ -104,3 +109,120 @@ namespace FreeSql.Tests.Sqlite } } } + +public static class DeleteExtensions +{ + public static string ToSqlCascade(this IDelete that) + { + var delete = that as DeleteProvider; + if (delete == null) return null; + if (delete._whereTimes <= 0 || delete._where.Length == 0) return null; + if (LocalGetNavigates(delete._table).Any() == false) return that.ToSql(); + + var fsql = delete._orm; + var sb = new StringBuilder(); + Dictionary eachdic = new Dictionary(); + + var rootSel = fsql.Select().AsType(delete._table.Type).Where(delete._where.ToString()); + var rootItems = rootSel.ToList(); + LocalEach(delete._table.Type, rootItems, true); + return sb.ToString(); + + List> LocalGetNavigates(TableInfo tb) + { + return tb.Properties.Where(a => tb.ColumnsByCs.ContainsKey(a.Key) == false) + .Select(a => new NativeTuple(tb.GetTableRef(a.Key, false), a.Value)) + .Where(a => a.Item1 != null && a.Item1.RefType != TableRefType.ManyToOne) + .ToList(); + } + void LocalEach(Type itemType, List items, bool isOneToOne) + { + items = items?.Where(item => + { + var itemKeystr = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(fsql, itemType, item, false); + var eachdicKey = $"{itemType.FullName},{itemKeystr}"; + if (eachdic.ContainsKey(eachdicKey)) return false; + eachdic.Add(eachdicKey, true); + return true; + }).ToList(); + if (items?.Any() != true) return; + + var tb = fsql.CodeFirst.GetTableByEntity(itemType); + var navs = LocalGetNavigates(tb); + + var otos = navs.Where(a => a.Item1.RefType == TableRefType.OneToOne).ToList(); + if (otos.Any()) + { + foreach (var oto in otos) + { + var childsSel = fsql.Select().AsType(oto.Item1.RefEntityType) as Select1Provider; + var refitems = items.Select(item => + { + var refitem = oto.Item1.RefEntityType.CreateInstanceGetDefaultValue(); + for (var a = 0; a < oto.Item1.Columns.Count; a++) + { + var colval = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetPropertyValue(tb, item, oto.Item1.Columns[a].CsName); + FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(childsSel._tables[0].Table, refitem, oto.Item1.RefColumns[a].CsName, colval); + } + return refitem; + }).ToList(); + + childsSel.Where(childsSel._commonUtils.WhereItems(oto.Item1.RefColumns.ToArray(), "a.", refitems)); + var childs = childsSel.ToList(); + LocalEach(oto.Item1.RefEntityType, childs, false); + } + } + + var otms = navs.Where(a => a.Item1.RefType == TableRefType.OneToMany).ToList(); + if (otms.Any()) + { + foreach (var otm in otms) + { + var childsSel = fsql.Select().AsType(otm.Item1.RefEntityType) as Select1Provider; + var refitems = items.Select(item => + { + var refitem = otm.Item1.RefEntityType.CreateInstanceGetDefaultValue(); + for (var a = 0; a < otm.Item1.Columns.Count; a++) + { + var colval = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetPropertyValue(tb, item, otm.Item1.Columns[a].CsName); + FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(childsSel._tables[0].Table, refitem, otm.Item1.RefColumns[a].CsName, colval); + } + return refitem; + }).ToList(); + + childsSel.Where(childsSel._commonUtils.WhereItems(otm.Item1.RefColumns.ToArray(), "a.", refitems)); + var childs = childsSel.ToList(); + LocalEach(otm.Item1.RefEntityType, childs, true); + } + } + + var mtms = navs.Where(a => a.Item1.RefType == TableRefType.ManyToMany).ToList(); + if (mtms.Any()) + { + foreach (var mtm in mtms) + { + var childsSel = fsql.Select().AsType(mtm.Item1.RefMiddleEntityType) as Select1Provider; + var miditems = items.Select(item => + { + var refitem = mtm.Item1.RefMiddleEntityType.CreateInstanceGetDefaultValue(); + for (var a = 0; a < mtm.Item1.Columns.Count; a++) + { + var colval = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetPropertyValue(tb, item, mtm.Item1.Columns[a].CsName); + FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(childsSel._tables[0].Table, refitem, mtm.Item1.MiddleColumns[a].CsName, colval); + } + return refitem; + }).ToList(); + + childsSel.Where(childsSel._commonUtils.WhereItems(mtm.Item1.MiddleColumns.Take(mtm.Item1.Columns.Count).ToArray(), "a.", miditems)); + var childs = childsSel.ToList(); + LocalEach(mtm.Item1.RefEntityType, childs, true); + } + } + + var delSql = fsql.Delete().AsType(itemType).WhereDynamic(items).ToSql(); + if (string.IsNullOrWhiteSpace(delSql)) throw new Exception($"ToSqlCascade 失败"); + if (sb.Length > 0) sb.Append("\r\n\r\n;\r\n\r\n"); + sb.Append(delSql); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs index 2fa2cc42..4d09e927 100644 --- a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs @@ -373,6 +373,8 @@ WHERE (((a.""Name"") in (SELECT s.""Title"" as1 var ddd = g.sqlite.Select().LeftJoin(d => d.ParentCode == d.Parent.Code).ToTreeList(); Assert.Single(ddd); Assert.Equal(2, ddd[0].Childs.Count); + + var sql = g.sqlite.Delete().Where(a => a.Code == "001").ToSqlCascade(); } public class District { @@ -1281,6 +1283,7 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title"" }; Assert.Equal(5, g.sqlite.Insert(model4s).ExecuteAffrows()); + var by0 = g.sqlite.Select() .Where(a => a.model2id <= model1.id) .ToList(); @@ -1305,6 +1308,8 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title"" .Where(a => a.id <= model1.id) .ToList(); by1.IncludeByPropertyName(g.sqlite, "model2.childs", "model2111Idaaa=model2id"); + + by1.IncludeByPropertyNameAsync(g.sqlite, "model2.childs", "model2111Idaaa=model2id"); var t1 = g.sqlite.Select() .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id)) .Where(a => a.id <= model1.id) @@ -2233,6 +2238,8 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title"" }) }); + var sql = g.sqlite.Delete().Where(a => a.Code == "100000").ToSqlCascade(); + var t1 = fsql.Select() .InnerJoin(a => a.ParentCode == a.Parent.Code) .Where(a => a.Code == "110101") diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index 3c7db3ce..0c791e84 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -201,7 +201,8 @@ public static partial class FreeSqlGlobalExtensions var value = dr.GetString(index); var t = typeof(T); var fs = _dicGetFields.GetOrAdd(t, t2 => t2.GetFields()); - foreach (var f in fs) { + foreach (var f in fs) + { var attr = f.GetCustomAttributes(typeof(DescriptionAttribute), false)?.FirstOrDefault() as DescriptionAttribute; if (attr?.Description == value || f.Name == value) return Enum.Parse(t, f.Name, true); } @@ -343,6 +344,29 @@ public static partial class FreeSqlGlobalExtensions /// public static List IncludeByPropertyName(this List list, IFreeSql orm, string property, string where = null, int take = 0, string select = null) where T1 : class { +#if net40 + return IncludeByPropertyNameSyncOrAsync(false, list, orm, property, where, take, select); +#else + var task = IncludeByPropertyNameSyncOrAsync(false, list, orm, property, where, take, select); + if (task.Exception != null) throw task.Exception.InnerException ?? task.Exception; + return task.Result; +#endif + } +#if net40 +#else + public static Task> IncludeByPropertyNameAsync(this List list, IFreeSql orm, string property, string where = null, int take = 0, string select = null) where T1 : class + { + return IncludeByPropertyNameSyncOrAsync(true, list, orm, property, where, take, select); + } +#endif + static +#if net40 + List +#else + async Task> +#endif + IncludeByPropertyNameSyncOrAsync(bool isAsync, List list, IFreeSql orm, string property, string where = null, int take = 0, string select = null) where T1 : class + { if (orm.CodeFirst.IsAutoSyncStructure) { var tb = orm.CodeFirst.GetTableByEntity(typeof(T1)); @@ -360,7 +384,13 @@ public static partial class FreeSqlGlobalExtensions { if (props.Length > 1) IncludeByPropertyName(list, orm, string.Join(".", props.Take(props.Length - 1))); - IncludeManyByPropertyNameCommonGetSelect(orm, property, where, take, select).SetList(list); + var imsel = IncludeManyByPropertyNameCommonGetSelect(orm, property, where, take, select); +#if net40 + imsel.SetList(list); +#else + if (isAsync) await imsel.SetListAsync(list); + else imsel.SetList(list); +#endif return list; } var tbtr = t1tb.GetTableRef(props[0], true); @@ -388,7 +418,13 @@ public static partial class FreeSqlGlobalExtensions }; }).GroupBy(a => a.key).ToDictionary(a => a.Key, a => a); refsel.WhereDynamic(listdic.Values.Select(a => a.First().refitem).ToList()); + +#if net40 var reflist = refsel.ToList(); +#else + var reflist = isAsync ? await refsel.ToListAsync() : refsel.ToList(); +#endif + reflist.ForEach(refitem => { var key = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(orm, reftb.Type, refitem, false); @@ -473,7 +509,7 @@ public static partial class FreeSqlGlobalExtensions incMethod.MakeGenericMethod(reftb.Type).Invoke(sel, new object[] { navigateSelector, null }); return sel; } -#endregion + #endregion #region ToTreeList() 父子分类 /// @@ -1162,7 +1198,7 @@ SELECT "); } #endregion -#endregion - + #endregion + }