diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index da7ace6b..bdd16ff9 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -538,5 +538,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs index be255299..2fa2cc42 100644 --- a/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs @@ -1284,7 +1284,7 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title"" var by0 = g.sqlite.Select() .Where(a => a.model2id <= model1.id) .ToList(); - by0.IncludeMany(g.sqlite, "childs", "model2111Idaaa=model2id", 2, "id"); + by0.IncludeByPropertyName(g.sqlite, "childs", "model2111Idaaa=model2id", 2, "id"); var t0 = g.sqlite.Select() .IncludeMany(a => a.childs.Where(m3 => m3.model2111Idaaa == a.model2id)) @@ -1304,7 +1304,7 @@ WHERE (((cast(a.""Id"" as character)) in (SELECT b.""Title"" var by1 = g.sqlite.Select() .Where(a => a.id <= model1.id) .ToList(); - by1.IncludeMany(g.sqlite, "model2.childs", "model2111Idaaa=model2id"); + by1.IncludeByPropertyName(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) diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index f7c88550..fed344ff 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -326,36 +326,77 @@ public static partial class FreeSqlGlobalExtensions } #endif /// - /// 本方法实现从已知的内存 List 数据,进行和 ISelect.IncludeMany 相同功能的贪婪加载 - /// 示例:new List<Song>(new[] { song1, song2, song3 }).IncludeMany(fsql, "Tags", "ParentId=Id", 5, "Id,Name"); + /// 本方法实现从已知的内存 List 数据,进行和 ISelect.IncludeMany/Include 相同功能的贪婪加载 + /// 集合:new List<Song>(new[] { song1, song2, song3 }).IncludeByPropertyName(fsql, "Tags", "ParentId=Id", 5, "Id,Name"); + /// 普通:new List<Song>(new[] { song1, song2, song3 }).IncludeByPropertyName(fsql, "Catetory"); + /// ---普通属性 where/take/select 参数将无效 /// 文档:https://github.com/dotnetcore/FreeSql/wiki/%E8%B4%AA%E5%A9%AA%E5%8A%A0%E8%BD%BD /// /// /// /// - /// 选择一个集合属性 - /// 设置临时的关系映射,格式:子类属性=T1属性 - /// 每个子集合只取条数 - /// 设置只查询部分字段 + /// 选择一个集合或普通属性 + /// 设置临时的子集合关系映射,格式:子类属性=T1属性 + /// 设置子集合只取条数 + /// 设置子集合只查询部分字段 /// /// - /// - public static List IncludeMany(this List list, IFreeSql orm, string property, string where = null, int take = 0, string select = null) where T1 : class + public static List IncludeByPropertyName(this List list, IFreeSql orm, string property, string where = null, int take = 0, string select = null) where T1 : class { - if (list == null || list.Any() == false) return list; - IncludeManyByPropertyNameCommonGetSelect(orm, property, where, take, select).SetList(list); + if (orm.CodeFirst.IsAutoSyncStructure) + { + var tb = orm.CodeFirst.GetTableByEntity(typeof(T1)); + if (tb == null || tb.Primarys.Any() == false) + (orm.CodeFirst as CodeFirstProvider)._dicSycedTryAdd(typeof(T1)); //._dicSyced.TryAdd(typeof(TReturn), true); + } + var props = property.Split('.'); + var t1tb = orm.CodeFirst.GetTableByEntity(typeof(T1)); + var t1sel = orm.Select() as Select1Provider; + var t1expFul = t1sel.ConvertStringPropertyToExpression(property, true); + var t1exp = props.Length == 1 ? t1expFul : t1sel.ConvertStringPropertyToExpression(props[0], true); + if (t1expFul == null) throw new ArgumentException($"{nameof(property)} 无法解析为表达式树"); + var propElementType = t1expFul.Type.GetGenericArguments().FirstOrDefault() ?? t1expFul.Type.GetElementType(); + if (propElementType != null) //IncludeMany + { + if (props.Length > 1) + IncludeByPropertyName(list, orm, string.Join(".", props.Take(props.Length - 1))); + IncludeManyByPropertyNameCommonGetSelect(orm, property, where, take, select).SetList(list); + return list; + } + var tbtr = t1tb.GetTableRef(props[0], true); + if (tbtr == null) throw new ArgumentException($"{nameof(property)} 参数错误,它不是有效的导航属性"); + var reftb = orm.CodeFirst.GetTableByEntity(t1exp.Type); + var refsel = orm.Select().AsType(t1exp.Type) as Select1Provider; + if (props.Length > 1) + { + var refexp = refsel.ConvertStringPropertyToExpression(string.Join(".", props.Skip(1)), true); + refsel.Include(Expression.Lambda>(refexp, refsel._tables[0].Parameter)); + } + var listdic = list.Select(item => + { + var refitem = t1exp.Type.CreateInstanceGetDefaultValue(); + for (var a = 0; a < tbtr.Columns.Count; a++) + { + var colval = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetPropertyValue(t1tb, item, tbtr.Columns[a].CsName); + FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(reftb, refitem, tbtr.RefColumns[a].CsName, colval); + } + return new + { + item, + refitem, + key = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(orm, reftb.Type, refitem, false) + }; + }).GroupBy(a => a.key).ToDictionary(a => a.Key, a => a); + refsel.WhereDynamic(listdic.Values.Select(a => a.First().refitem).ToList()); + var reflist = refsel.ToList(); + reflist.ForEach(refitem => + { + var key = FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(orm, reftb.Type, refitem, false); + foreach (var listitem in listdic[key]) + FreeSql.Extensions.EntityUtil.EntityUtilExtensions.SetPropertyValue(t1tb, listitem.item, property, refitem); + }); return list; } -#if net40 -#else - async public static Task> IncludeManyAsync(this List list, IFreeSql orm, string property, string where = null, int take = 0, string select = null) where T1 : class - { - if (list == null || list.Any() == false) return list; - await IncludeManyByPropertyNameCommonGetSelect(orm, property, where, take, select).SetListAsync(list); - return list; - } -#endif - static Select1Provider IncludeManyByPropertyNameCommonGetSelect(IFreeSql orm, string property, string where = null, int take = 0, string select = null) where T1 : class { if (orm.CodeFirst.IsAutoSyncStructure) @@ -432,9 +473,9 @@ public static partial class FreeSqlGlobalExtensions incMethod.MakeGenericMethod(reftb.Type).Invoke(sel, new object[] { navigateSelector, null }); return sel; } - #endregion +#endregion - #region ToTreeList() 父子分类 +#region ToTreeList() 父子分类 /// /// 查询数据,加工为树型 List 返回 /// 注意:实体需要配置父子导航属性 @@ -487,9 +528,9 @@ public static partial class FreeSqlGlobalExtensions return list.Except(list.SelectMany(a => FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityValueWithPropertyName(select._orm, tb.Type, a, navs[0].Property.Name) as IEnumerable)).ToList(); } #endif - #endregion +#endregion - #region AsTreeCte(..) 递归查询 +#region AsTreeCte(..) 递归查询 static ConcurrentDictionary _dicMySqlVersion = new ConcurrentDictionary(); /// /// 使用递归 CTE 查询树型的所有子记录,或者所有父记录。 @@ -717,9 +758,9 @@ SELECT "); nsselsb.Clear(); return newSelect; } - #endregion +#endregion - #region OrderBy Random 随机排序 +#region OrderBy Random 随机排序 /// /// 随机排序 @@ -759,9 +800,9 @@ SELECT "); } throw new NotSupportedException($"{s0p._orm.Ado.DataType} 不支持 OrderByRandom 随机排序"); } - #endregion +#endregion - #region IFreeSql Insert/Update/InsertOrUpdate/Delete Dictionary +#region IFreeSql Insert/Update/InsertOrUpdate/Delete Dictionary /// /// 插入数据字典 Dictionary<string, object> /// @@ -871,7 +912,7 @@ SELECT "); return deleteDict ?? new DeleteDictImpl(freesql); } - #region InsertDictImpl +#region InsertDictImpl public class InsertDictImpl { internal readonly InsertProvider> _insertProvider; @@ -934,9 +975,9 @@ SELECT "); return this; } } - #endregion +#endregion - #region UpdateDictImpl +#region UpdateDictImpl public class UpdateDictImpl { internal readonly UpdateProvider> _updateProvider; @@ -1022,9 +1063,9 @@ SELECT "); return this; } } - #endregion +#endregion - #region InsertOrUpdateDictImpl +#region InsertOrUpdateDictImpl public class InsertOrUpdateDictImpl { internal readonly InsertOrUpdateProvider> _insertOrUpdateProvider; @@ -1075,9 +1116,9 @@ SELECT "); return this; } } - #endregion +#endregion - #region DeleteDictImpl +#region DeleteDictImpl public class DeleteDictImpl { internal readonly DeleteProvider> _deleteProvider; @@ -1120,7 +1161,7 @@ SELECT "); return this; } } - #endregion +#endregion - #endregion +#endregion } diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index cc9f8df9..cf23062f 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -4653,22 +4653,23 @@ 即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?) - + - 本方法实现从已知的内存 List 数据,进行和 ISelect.IncludeMany 相同功能的贪婪加载 - 示例:new List<Song>(new[] { song1, song2, song3 }).IncludeMany(fsql, "Tags", "ParentId=Id", 5, "Id,Name"); + 本方法实现从已知的内存 List 数据,进行和 ISelect.IncludeMany/Include 相同功能的贪婪加载 + 集合:new List<Song>(new[] { song1, song2, song3 }).IncludeByPropertyName(fsql, "Tags", "ParentId=Id", 5, "Id,Name"); + 普通:new List<Song>(new[] { song1, song2, song3 }).IncludeByPropertyName(fsql, "Catetory"); + ---普通属性 where/take/select 参数将无效 文档:https://github.com/dotnetcore/FreeSql/wiki/%E8%B4%AA%E5%A9%AA%E5%8A%A0%E8%BD%BD - 选择一个集合属性 - 设置临时的关系映射,格式:子类属性=T1属性 - 每个子集合只取条数 - 设置只查询部分字段 + 选择一个集合或普通属性 + 设置临时的子集合关系映射,格式:子类属性=T1属性 + 设置子集合只取条数 + 设置子集合只查询部分字段 -