mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
- 增加 ISelect.ToTreeList 扩展方法查询数据,加工为树型 List;(注意:实体需要配置父子导航属性)
This commit is contained in:
parent
529be7d9d2
commit
0effad75e4
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<RootNamespace>FreeSql.Tests.VB</RootNamespace>
|
||||
@ -15,6 +15,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Extensions\FreeSql.Extensions.BaseEntity\FreeSql.Extensions.BaseEntity.csproj" />
|
||||
<ProjectReference Include="..\Extensions\FreeSql.Extensions.LazyLoading\FreeSql.Extensions.LazyLoading.csproj" />
|
||||
<ProjectReference Include="..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
|
||||
<ProjectReference Include="..\Providers\FreeSql.Provider.SqlServer\FreeSql.Provider.SqlServer.csproj" />
|
||||
|
@ -1,4 +1,5 @@
|
||||
Imports System
|
||||
Imports FreeSql.DataAnnotations
|
||||
Imports Xunit
|
||||
|
||||
Namespace FreeSql.Tests.VB
|
||||
@ -38,6 +39,17 @@ Namespace FreeSql.Tests.VB
|
||||
|
||||
Dim List9 = g.sqlserver.Select(Of Testvb).IncludeMany(Function(a) a.Testvb2s).ToList()
|
||||
|
||||
BaseEntity.Initialization(g.sqlserver)
|
||||
Dim cowR As CowRecord = New CowRecord
|
||||
cowR.Id = 1
|
||||
cowR.Lact = 1
|
||||
cowR.VetCount = 1
|
||||
cowR.Save()
|
||||
|
||||
cowR.VetCount += 1
|
||||
cowR.Update()
|
||||
|
||||
|
||||
|
||||
End Sub
|
||||
End Class
|
||||
@ -58,3 +70,52 @@ Class Testvb2
|
||||
Property Testvb As Testvb
|
||||
Property Context As String
|
||||
End Class
|
||||
|
||||
<Index("uk_Primary", "Id,Lact", True)>
|
||||
Public Class CowRecord
|
||||
Inherits BaseEntity(Of CowRecord)
|
||||
Private _Id As Integer
|
||||
Private _Lact As Integer
|
||||
Private _Pen As Integer
|
||||
Private _BDAT As Date?
|
||||
Private _FDAT As Date?
|
||||
Private _DDAT As Date?
|
||||
Private _EDAT As Date?
|
||||
Private _ARDAT As Date?
|
||||
Private _MKDAT As Date?
|
||||
Private _BFDAT As Date?
|
||||
Private _USDAT As Date?
|
||||
Private _RC As Integer
|
||||
Private _DMLK1 As Integer
|
||||
Private _VetCount As Integer
|
||||
|
||||
<Column(IsPrimary:=True)>
|
||||
Public Property Id As Integer
|
||||
Get
|
||||
Return _Id
|
||||
End Get
|
||||
Set(value As Integer)
|
||||
_Id = value
|
||||
End Set
|
||||
End Property
|
||||
|
||||
|
||||
<Column(IsPrimary:=True)>
|
||||
Public Property Lact As Integer
|
||||
Get
|
||||
Return _Lact
|
||||
End Get
|
||||
Set(value As Integer)
|
||||
_Lact = value
|
||||
End Set
|
||||
End Property
|
||||
|
||||
Public Property VetCount As Integer
|
||||
Get
|
||||
Return _VetCount
|
||||
End Get
|
||||
Set(value As Integer)
|
||||
_VetCount = value
|
||||
End Set
|
||||
End Property
|
||||
End Class
|
||||
|
@ -1,6 +1,7 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace FreeSql.Tests
|
||||
@ -318,6 +319,7 @@ namespace FreeSql.Tests
|
||||
cts[1].Goodss.Clear();
|
||||
cts[1].Goodss.Add(new Goods { Name = "ÉÌÆ·55" });
|
||||
repo.Update(cts);
|
||||
|
||||
}
|
||||
[Table(Name = "EAUNL_OTM_CT")]
|
||||
class Cagetory
|
||||
@ -390,6 +392,7 @@ namespace FreeSql.Tests
|
||||
[Fact]
|
||||
public void EnableAddOrUpdateNavigateList_OneToMany_Parent()
|
||||
{
|
||||
g.sqlite.Delete<CagetoryParent>().Where("1=1").ExecuteAffrows();
|
||||
var repo = g.sqlite.GetRepository<CagetoryParent>();
|
||||
var cts = new[] {
|
||||
new CagetoryParent
|
||||
@ -412,9 +415,12 @@ namespace FreeSql.Tests
|
||||
})
|
||||
}
|
||||
};
|
||||
repo.DbContextOptions.EnableAddOrUpdateNavigateList = false; //关闭级联保存功能
|
||||
repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; //打开级联保存功能
|
||||
repo.Insert(cts);
|
||||
repo.SaveMany(cts[0], "Childs"); //指定保存 Childs 一对多属性
|
||||
|
||||
var treelist1 = repo.Select.ToTreeList();
|
||||
|
||||
//repo.SaveMany(cts[0], "Childs"); //指定保存 Childs 一对多属性
|
||||
cts[0].Name = "·ÖÀà11";
|
||||
cts[0].Childs.Clear();
|
||||
cts[1].Name = "·ÖÀà22";
|
||||
@ -427,6 +433,7 @@ namespace FreeSql.Tests
|
||||
cts[1].Childs.Clear();
|
||||
cts[1].Childs.Add(new CagetoryParent { Name = "·ÖÀà2_22" });
|
||||
repo.Update(cts);
|
||||
var treelist2 = repo.Select.ToTreeList();
|
||||
}
|
||||
[Table(Name = "EAUNL_OTMP_CT")]
|
||||
class CagetoryParent
|
||||
|
@ -1,5 +1,6 @@
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
@ -246,6 +247,61 @@ public static partial class FreeSqlGlobalExtensions
|
||||
await select.SetListAsync(list);
|
||||
return list;
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region ToTreeList() 父子分类
|
||||
/// <summary>
|
||||
/// 查询数据,加工为树型 List 返回<para></para>
|
||||
/// 注意:实体需要配置父子导航属性
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <param name="that"></param>
|
||||
/// <returns></returns>
|
||||
public static List<T1> ToTreeList<T1>(this ISelect<T1> that) where T1 : class
|
||||
{
|
||||
var select = that as Select1Provider<T1>;
|
||||
var tb = select._tables[0].Table;
|
||||
var navs = tb.Properties.Select(a => tb.GetTableRef(a.Key, false))
|
||||
.Where(a => a != null &&
|
||||
a.RefType == FreeSql.Internal.Model.TableRefType.OneToMany &&
|
||||
a.RefEntityType == tb.Type).ToArray();
|
||||
|
||||
if (navs.Length != 1) return select.ToList();
|
||||
var list = select.ToList();
|
||||
|
||||
select._trackToList = null;
|
||||
select._includeToList.Clear();
|
||||
var navigateSelectorParamExp = select._tables[0].Parameter ?? Expression.Parameter(typeof(T1), select._tables[0].Alias);
|
||||
var navigateSelector = Expression.Lambda<Func<T1, IEnumerable<T1>>>(Expression.MakeMemberAccess(navigateSelectorParamExp, navs[0].Property), navigateSelectorParamExp);
|
||||
select.IncludeMany(navigateSelector);
|
||||
select._includeManySubListOneToManyTempValue1 = list;
|
||||
select.SetList(list);
|
||||
return list.Except(list.SelectMany(a => FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityValueWithPropertyName(select._orm, tb.Type, a, navs[0].Property.Name) as IEnumerable<T1>)).ToList();
|
||||
}
|
||||
#if net40
|
||||
#else
|
||||
async public static System.Threading.Tasks.Task<List<T1>> ToTreeListAsync<T1>(this ISelect<T1> that) where T1 : class
|
||||
{
|
||||
var select = that as Select1Provider<T1>;
|
||||
var tb = select._tables[0].Table;
|
||||
var navs = tb.Properties.Select(a => tb.GetTableRef(a.Key, false))
|
||||
.Where(a => a != null &&
|
||||
a.RefType == FreeSql.Internal.Model.TableRefType.OneToMany &&
|
||||
a.RefEntityType == tb.Type).ToArray();
|
||||
|
||||
if (navs.Length != 1) return await select.ToListAsync();
|
||||
var list = await select.ToListAsync();
|
||||
|
||||
select._trackToList = null;
|
||||
select._includeToList.Clear();
|
||||
var navigateSelectorParamExp = select._tables[0].Parameter ?? Expression.Parameter(typeof(T1), select._tables[0].Alias);
|
||||
var navigateSelector = Expression.Lambda<Func<T1, IEnumerable<T1>>>(Expression.MakeMemberAccess(navigateSelectorParamExp, navs[0].Property), navigateSelectorParamExp);
|
||||
select.IncludeMany(navigateSelector);
|
||||
select._includeManySubListOneToManyTempValue1 = list;
|
||||
select.SetList(list);
|
||||
return list.Except(list.SelectMany(a => FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityValueWithPropertyName(select._orm, tb.Type, a, navs[0].Property.Name) as IEnumerable<T1>)).ToList();
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
}
|
@ -3080,6 +3080,15 @@
|
||||
<param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:FreeSqlGlobalExtensions.ToTreeList``1(FreeSql.ISelect{``0})">
|
||||
<summary>
|
||||
查询数据,加工为树型 List 返回<para></para>
|
||||
注意:实体需要配置父子导航属性
|
||||
</summary>
|
||||
<typeparam name="T1"></typeparam>
|
||||
<param name="that"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:System.Linq.Expressions.LambadaExpressionExtensions.And``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
|
||||
<summary>
|
||||
使用 and 拼接两个 lambda 表达式
|
||||
|
@ -23,18 +23,18 @@ namespace FreeSql.Internal.CommonProvider
|
||||
protected string _select = "SELECT ", _orderby, _groupby, _having;
|
||||
protected StringBuilder _where = new StringBuilder();
|
||||
protected List<DbParameter> _params = new List<DbParameter>();
|
||||
protected List<SelectTableInfo> _tables = new List<SelectTableInfo>();
|
||||
internal protected List<SelectTableInfo> _tables = new List<SelectTableInfo>();
|
||||
protected List<Func<Type, string, string>> _tableRules = new List<Func<Type, string, string>>();
|
||||
protected Func<Type, string, string> _aliasRule;
|
||||
protected string _tosqlAppendContent;
|
||||
protected StringBuilder _join = new StringBuilder();
|
||||
protected IFreeSql _orm;
|
||||
internal protected IFreeSql _orm;
|
||||
protected CommonUtils _commonUtils;
|
||||
protected CommonExpression _commonExpression;
|
||||
protected DbTransaction _transaction;
|
||||
protected DbConnection _connection;
|
||||
protected Action<object> _trackToList;
|
||||
protected List<Action<object>> _includeToList = new List<Action<object>>();
|
||||
internal protected Action<object> _trackToList;
|
||||
internal protected List<Action<object>> _includeToList = new List<Action<object>>();
|
||||
#if net40
|
||||
#else
|
||||
protected List<Func<object, Task>> _includeToListAsync = new List<Func<object, Task>>();
|
||||
|
@ -659,6 +659,93 @@ namespace FreeSql.Internal.CommonProvider
|
||||
foreach (var item in list)
|
||||
setListValue(item, null);
|
||||
|
||||
Action<List<TNavigate>, TableInfo> fillOneToManyData = (subList, tbref2) =>
|
||||
{
|
||||
if (subList.Any() == false)
|
||||
{
|
||||
foreach (var item in list)
|
||||
setListValue(item, new List<TNavigate>());
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<string, List<Tuple<T1, List<TNavigate>>>> dicList = new Dictionary<string, List<Tuple<T1, List<TNavigate>>>>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (tbref.Columns.Count == 1)
|
||||
{
|
||||
var dicListKey = getListValue(item, tbref.Columns[0].CsName, 0)?.ToString();
|
||||
if (dicListKey == null) continue;
|
||||
var dicListVal = Tuple.Create(item, new List<TNavigate>());
|
||||
if (dicList.TryGetValue(dicListKey, out var items) == false)
|
||||
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
|
||||
items.Add(dicListVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (var z = 0; z < tbref.Columns.Count; z++)
|
||||
{
|
||||
if (z > 0) sb.Append("*$*");
|
||||
sb.Append(getListValue(item, tbref.Columns[z].CsName, z));
|
||||
}
|
||||
var dicListKey = sb.ToString();
|
||||
var dicListVal = Tuple.Create(item, new List<TNavigate>());
|
||||
if (dicList.TryGetValue(dicListKey, out var items) == false)
|
||||
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
|
||||
items.Add(dicListVal);
|
||||
sb.Clear();
|
||||
}
|
||||
}
|
||||
var parentNavs = new List<string>();
|
||||
foreach (var navProp in tbref2.Properties)
|
||||
{
|
||||
if (tbref2.ColumnsByCs.ContainsKey(navProp.Key)) continue;
|
||||
if (tbref2.ColumnsByCsIgnore.ContainsKey(navProp.Key)) continue;
|
||||
var tr2ref = tbref2.GetTableRef(navProp.Key, false);
|
||||
if (tr2ref == null) continue;
|
||||
if (tr2ref.RefType != TableRefType.ManyToOne) continue;
|
||||
if (tr2ref.RefEntityType != tb.Type) continue;
|
||||
parentNavs.Add(navProp.Key);
|
||||
}
|
||||
foreach (var nav in subList)
|
||||
{
|
||||
string key = null;
|
||||
if (tbref.RefColumns.Count == 1)
|
||||
{
|
||||
key = _orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[0].CsName).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (var z = 0; z < tbref.RefColumns.Count; z++)
|
||||
{
|
||||
if (z > 0) sb.Append("*$*");
|
||||
sb.Append(_orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[z].CsName));
|
||||
}
|
||||
key = sb.ToString();
|
||||
sb.Clear();
|
||||
}
|
||||
if (dicList.TryGetValue(key, out var t1items) == false) continue;
|
||||
foreach (var t1item in t1items)
|
||||
t1item.Item2.Add(nav);
|
||||
|
||||
//将子集合的,多对一,对象设置为当前对象
|
||||
foreach (var parentNav in parentNavs)
|
||||
foreach (var t1item in t1items)
|
||||
_orm.SetEntityValueWithPropertyName(tbref.RefMiddleEntityType, nav, parentNav, t1item.Item1);
|
||||
}
|
||||
foreach (var t1items in dicList.Values)
|
||||
foreach (var t1item in t1items)
|
||||
setListValue(t1item.Item1, t1item.Item2);
|
||||
dicList.Clear();
|
||||
};
|
||||
|
||||
if (tbref.RefType == TableRefType.OneToMany && _includeManySubListOneToManyTempValue1 != null && _includeManySubListOneToManyTempValue1 is List<TNavigate>)
|
||||
{
|
||||
fillOneToManyData(_includeManySubListOneToManyTempValue1 as List<TNavigate>, _commonUtils.GetTableByEntity(tbref.RefEntityType));
|
||||
return;
|
||||
}
|
||||
|
||||
var subSelect = _orm.Select<TNavigate>()
|
||||
.DisableGlobalFilter()
|
||||
.WithConnection(_connection)
|
||||
@ -794,83 +881,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
}
|
||||
}
|
||||
|
||||
if (subList.Any() == false)
|
||||
{
|
||||
foreach (var item in list)
|
||||
setListValue(item, new List<TNavigate>());
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<string, List<Tuple<T1, List<TNavigate>>>> dicList = new Dictionary<string, List<Tuple<T1, List<TNavigate>>>>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (tbref.Columns.Count == 1)
|
||||
{
|
||||
var dicListKey = getListValue(item, tbref.Columns[0].CsName, 0)?.ToString();
|
||||
if (dicListKey == null) continue;
|
||||
var dicListVal = Tuple.Create(item, new List<TNavigate>());
|
||||
if (dicList.TryGetValue(dicListKey, out var items) == false)
|
||||
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
|
||||
items.Add(dicListVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (var z = 0; z < tbref.Columns.Count; z++)
|
||||
{
|
||||
if (z > 0) sb.Append("*$*");
|
||||
sb.Append(getListValue(item, tbref.Columns[z].CsName, z));
|
||||
}
|
||||
var dicListKey = sb.ToString();
|
||||
var dicListVal = Tuple.Create(item, new List<TNavigate>());
|
||||
if (dicList.TryGetValue(dicListKey, out var items) == false)
|
||||
dicList.Add(dicListKey, items = new List<Tuple<T1, List<TNavigate>>>());
|
||||
items.Add(dicListVal);
|
||||
sb.Clear();
|
||||
}
|
||||
}
|
||||
var parentNavs = new List<string>();
|
||||
foreach (var navProp in tbref2.Properties)
|
||||
{
|
||||
if (tbref2.ColumnsByCs.ContainsKey(navProp.Key)) continue;
|
||||
if (tbref2.ColumnsByCsIgnore.ContainsKey(navProp.Key)) continue;
|
||||
var tr2ref = tbref2.GetTableRef(navProp.Key, false);
|
||||
if (tr2ref == null) continue;
|
||||
if (tr2ref.RefType != TableRefType.ManyToOne) continue;
|
||||
if (tr2ref.RefEntityType != tb.Type) continue;
|
||||
parentNavs.Add(navProp.Key);
|
||||
}
|
||||
foreach (var nav in subList)
|
||||
{
|
||||
string key = null;
|
||||
if (tbref.RefColumns.Count == 1)
|
||||
{
|
||||
key = _orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[0].CsName).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (var z = 0; z < tbref.RefColumns.Count; z++)
|
||||
{
|
||||
if (z > 0) sb.Append("*$*");
|
||||
sb.Append(_orm.GetEntityValueWithPropertyName(tbref.RefEntityType, nav, tbref.RefColumns[z].CsName));
|
||||
}
|
||||
key = sb.ToString();
|
||||
sb.Clear();
|
||||
}
|
||||
if (dicList.TryGetValue(key, out var t1items) == false) return;
|
||||
foreach (var t1item in t1items)
|
||||
t1item.Item2.Add(nav);
|
||||
|
||||
//将子集合的,多对一,对象设置为当前对象
|
||||
foreach (var parentNav in parentNavs)
|
||||
foreach (var t1item in t1items)
|
||||
_orm.SetEntityValueWithPropertyName(tbref.RefMiddleEntityType, nav, parentNav, t1item.Item1);
|
||||
}
|
||||
foreach (var t1items in dicList.Values)
|
||||
foreach (var t1item in t1items)
|
||||
setListValue(t1item.Item1, t1item.Item2);
|
||||
dicList.Clear();
|
||||
fillOneToManyData(subList, tbref2);
|
||||
}
|
||||
break;
|
||||
case TableRefType.ManyToMany:
|
||||
@ -1044,7 +1055,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
key = sb.ToString();
|
||||
sb.Clear();
|
||||
}
|
||||
if (dicList.TryGetValue(key, out var t1items) == false) return;
|
||||
if (dicList.TryGetValue(key, out var t1items) == false) continue;
|
||||
foreach (var t1item in t1items)
|
||||
t1item.Item2.Add(subList[a]);
|
||||
}
|
||||
@ -1065,6 +1076,7 @@ namespace FreeSql.Internal.CommonProvider
|
||||
return this;
|
||||
}
|
||||
|
||||
internal object _includeManySubListOneToManyTempValue1 = null;
|
||||
internal void SetList(IEnumerable<T1> list)
|
||||
{
|
||||
foreach (var include in _includeToList) include?.Invoke(list);
|
||||
|
Loading…
x
Reference in New Issue
Block a user