mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	AggregateRootRepository
This commit is contained in:
		@@ -800,5 +800,14 @@
 | 
				
			|||||||
            <param name="that"></param>
 | 
					            <param name="that"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:Microsoft.Extensions.DependencyInjection.FreeSqlRepositoryDependencyInjection.AddFreeRepository(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{FreeSql.FluentDataFilter},System.Reflection.Assembly[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            批量注入 Repository,可以参考代码自行调整
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="services"></param>
 | 
				
			||||||
 | 
					            <param name="globalDataFilter"></param>
 | 
				
			||||||
 | 
					            <param name="assemblies"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
    </members>
 | 
					    </members>
 | 
				
			||||||
</doc>
 | 
					</doc>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,9 @@
 | 
				
			|||||||
using FreeSql.Extensions.EntityUtil;
 | 
					using FreeSql.Extensions.EntityUtil;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections;
 | 
					using System.Collections;
 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Reflection;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql
 | 
					namespace FreeSql
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -156,7 +149,7 @@ namespace FreeSql
 | 
				
			|||||||
            get
 | 
					            get
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var query = _repository.Select.TrackToList(SelectAggregateRootTracking);
 | 
					                var query = _repository.Select.TrackToList(SelectAggregateRootTracking);
 | 
				
			||||||
                SelectAggregateRootNavigateReader(query, EntityType, "", new Stack<Type>());
 | 
					                query = AggregateRootUtils.GetAutoIncludeQuery(query);
 | 
				
			||||||
                return query;
 | 
					                return query;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -166,7 +159,7 @@ namespace FreeSql
 | 
				
			|||||||
        /// 2、返回的内容用,可用于配合重写仓储 override Select 属性<para></para>
 | 
					        /// 2、返回的内容用,可用于配合重写仓储 override Select 属性<para></para>
 | 
				
			||||||
        /// 返回内容:fsql.Select<T>().Include(...).IncludeMany(...) 
 | 
					        /// 返回内容:fsql.Select<T>().Include(...).IncludeMany(...) 
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        protected string SelectAggregateRootStaticCode => $"//fsql.Select<{EntityType.Name}>()\r\nthis.SelectDiy{SelectAggregateRootNavigateReader(1, EntityType, "", new Stack<Type>())}";
 | 
					        protected string SelectAggregateRootStaticCode => $"//fsql.Select<{EntityType.Name}>()\r\nthis.SelectDiy{AggregateRootUtils.GetAutoIncludeQueryStaicCode(Orm, EntityType)}";
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// ISelect.TrackToList 委托,数据返回后自动 Attach
 | 
					        /// ISelect.TrackToList 委托,数据返回后自动 Attach
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@@ -198,83 +191,40 @@ namespace FreeSql
 | 
				
			|||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        void SelectAggregateRootNavigateReader<T1>(ISelect<T1> currentQuery, Type entityType, string navigatePath, Stack<Type> ignores)
 | 
					        //void SelectAggregateRootNavigateReader<T1>(ISelect<T1> currentQuery, Type entityType, string navigatePath, Stack<Type> ignores)
 | 
				
			||||||
        {
 | 
					        //{
 | 
				
			||||||
            if (ignores.Any(a => a == entityType)) return;
 | 
					        //    if (ignores.Any(a => a == entityType)) return;
 | 
				
			||||||
            ignores.Push(entityType);
 | 
					        //    ignores.Push(entityType);
 | 
				
			||||||
            var table = Orm.CodeFirst.GetTableByEntity(entityType);
 | 
					        //    var table = Orm.CodeFirst.GetTableByEntity(entityType);
 | 
				
			||||||
            if (table == null) return;
 | 
					        //    if (table == null) return;
 | 
				
			||||||
            if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}.";
 | 
					        //    if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}.";
 | 
				
			||||||
            foreach (var tr in table.GetAllTableRef())
 | 
					        //    foreach (var tr in table.GetAllTableRef())
 | 
				
			||||||
            {
 | 
					        //    {
 | 
				
			||||||
                var tbref = tr.Value;
 | 
					        //        var tbref = tr.Value;
 | 
				
			||||||
                if (tbref.Exception != null) continue;
 | 
					        //        if (tbref.Exception != null) continue;
 | 
				
			||||||
                var navigateExpression = $"{navigatePath}{tr.Key}";
 | 
					        //        var navigateExpression = $"{navigatePath}{tr.Key}";
 | 
				
			||||||
                switch (tbref.RefType)
 | 
					        //        switch (tbref.RefType)
 | 
				
			||||||
                {
 | 
					        //        {
 | 
				
			||||||
                    case TableRefType.OneToOne:
 | 
					        //            case TableRefType.OneToOne:
 | 
				
			||||||
                        if (ignores.Any(a => a == tbref.RefEntityType)) break;
 | 
					        //                if (ignores.Any(a => a == tbref.RefEntityType)) break;
 | 
				
			||||||
                        currentQuery.IncludeByPropertyName(navigateExpression);
 | 
					        //                currentQuery.IncludeByPropertyName(navigateExpression);
 | 
				
			||||||
                        SelectAggregateRootNavigateReader(currentQuery, tbref.RefEntityType, navigateExpression, ignores);
 | 
					        //                SelectAggregateRootNavigateReader(currentQuery, tbref.RefEntityType, navigateExpression, ignores);
 | 
				
			||||||
                        break;
 | 
					        //                break;
 | 
				
			||||||
                    case TableRefType.OneToMany:
 | 
					        //            case TableRefType.OneToMany:
 | 
				
			||||||
                        var ignoresCopy = new Stack<Type>(ignores.ToArray());
 | 
					        //                var ignoresCopy = new Stack<Type>(ignores.ToArray());
 | 
				
			||||||
                        currentQuery.IncludeByPropertyName(navigateExpression, then =>
 | 
					        //                currentQuery.IncludeByPropertyName(navigateExpression, then =>
 | 
				
			||||||
                            SelectAggregateRootNavigateReader(then, tbref.RefEntityType, "", ignoresCopy));
 | 
					        //                    SelectAggregateRootNavigateReader(then, tbref.RefEntityType, "", ignoresCopy)); //variable 'then' of type 'FreeSql.ISelect`1[System.Object]' referenced from scope '', but it is not defined
 | 
				
			||||||
                        break;
 | 
					        //                break;
 | 
				
			||||||
                    case TableRefType.ManyToMany:
 | 
					        //            case TableRefType.ManyToMany:
 | 
				
			||||||
                        currentQuery.IncludeByPropertyName(navigateExpression);
 | 
					        //                currentQuery.IncludeByPropertyName(navigateExpression);
 | 
				
			||||||
                        break;
 | 
					        //                break;
 | 
				
			||||||
                    case TableRefType.PgArrayToMany:
 | 
					        //            case TableRefType.PgArrayToMany:
 | 
				
			||||||
                    case TableRefType.ManyToOne: //不属于聚合根
 | 
					        //            case TableRefType.ManyToOne: //不属于聚合根
 | 
				
			||||||
                        break;
 | 
					        //                break;
 | 
				
			||||||
                }
 | 
					        //        }
 | 
				
			||||||
            }
 | 
					        //    }
 | 
				
			||||||
            ignores.Pop();
 | 
					        //    ignores.Pop();
 | 
				
			||||||
        }
 | 
					        //}
 | 
				
			||||||
        string SelectAggregateRootNavigateReader(int depth, Type entityType, string navigatePath, Stack<Type> ignores)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var code = new StringBuilder();
 | 
					 | 
				
			||||||
            if (ignores.Any(a => a == entityType)) return null;
 | 
					 | 
				
			||||||
            ignores.Push(entityType);
 | 
					 | 
				
			||||||
            var table = Orm.CodeFirst.GetTableByEntity(entityType);
 | 
					 | 
				
			||||||
            if (table == null) return null;
 | 
					 | 
				
			||||||
            if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}.";
 | 
					 | 
				
			||||||
            foreach (var tr in table.GetAllTableRef())
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var tbref = tr.Value;
 | 
					 | 
				
			||||||
                if (tbref.Exception != null) continue;
 | 
					 | 
				
			||||||
                var navigateExpression = $"{navigatePath}{tr.Key}";
 | 
					 | 
				
			||||||
                var depthTab = "".PadLeft(depth * 4);
 | 
					 | 
				
			||||||
                var lambdaAlias = (char)((byte)'a' + (depth - 1));
 | 
					 | 
				
			||||||
                var lambdaStr = $"{lambdaAlias} => {lambdaAlias}.";
 | 
					 | 
				
			||||||
                switch (tbref.RefType)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case TableRefType.OneToOne:
 | 
					 | 
				
			||||||
                        if (ignores.Any(a => a == tbref.RefEntityType)) break;
 | 
					 | 
				
			||||||
                        code.Append("\r\n").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
					 | 
				
			||||||
                        code.Append(SelectAggregateRootNavigateReader(depth, tbref.RefEntityType, navigateExpression, ignores));
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case TableRefType.OneToMany:
 | 
					 | 
				
			||||||
                        code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
 | 
					 | 
				
			||||||
                        var thencode = SelectAggregateRootNavigateReader(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
 | 
					 | 
				
			||||||
                        if (thencode.Length > 0) code.Append(", then => then").Append(thencode);
 | 
					 | 
				
			||||||
                        code.Append(")");
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case TableRefType.ManyToMany:
 | 
					 | 
				
			||||||
                        code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case TableRefType.PgArrayToMany:
 | 
					 | 
				
			||||||
                        code.Append("\r\n//").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case TableRefType.ManyToOne: //不属于聚合根
 | 
					 | 
				
			||||||
                        code.Append("\r\n//").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ignores.Pop();
 | 
					 | 
				
			||||||
            return code.ToString();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
using FreeSql;
 | 
					using FreeSql;
 | 
				
			||||||
using FreeSql.Extensions.EntityUtil;
 | 
					using FreeSql.Extensions.EntityUtil;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.CommonProvider;
 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections;
 | 
					using System.Collections;
 | 
				
			||||||
@@ -8,7 +9,9 @@ using System.Collections.Concurrent;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Collections.ObjectModel;
 | 
					using System.Collections.ObjectModel;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Reflection;
 | 
					using System.Reflection;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static class AggregateRootUtils
 | 
					static class AggregateRootUtils
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -85,13 +88,13 @@ static class AggregateRootUtils
 | 
				
			|||||||
                switch (tbref.RefType)
 | 
					                switch (tbref.RefType)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    case TableRefType.OneToOne:
 | 
					                    case TableRefType.OneToOne:
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityBefore, propvalBefore);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore);
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityAfter, propvalAfter);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter);
 | 
				
			||||||
                        LocalCompareEntityValue(tbref.RefEntityType, propvalBefore, propvalAfter, null);
 | 
					                        LocalCompareEntityValue(tbref.RefEntityType, propvalBefore, propvalAfter, null);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    case TableRefType.OneToMany:
 | 
					                    case TableRefType.OneToMany:
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityBefore, propvalBefore);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore);
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityAfter, propvalAfter);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter);
 | 
				
			||||||
                        LocalCompareEntityValueCollection(tbref, propvalBefore as IEnumerable, propvalAfter as IEnumerable);
 | 
					                        LocalCompareEntityValueCollection(tbref, propvalBefore as IEnumerable, propvalAfter as IEnumerable);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    case TableRefType.ManyToMany:
 | 
					                    case TableRefType.ManyToMany:
 | 
				
			||||||
@@ -201,7 +204,7 @@ static class AggregateRootUtils
 | 
				
			|||||||
                        var propval = table.GetPropertyValue(entity, prop.Name);
 | 
					                        var propval = table.GetPropertyValue(entity, prop.Name);
 | 
				
			||||||
                        statckPath.Push(prop.Name);
 | 
					                        statckPath.Push(prop.Name);
 | 
				
			||||||
                        stackValues.Add(propval);
 | 
					                        stackValues.Add(propval);
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entity, propval);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propval);
 | 
				
			||||||
                        callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
 | 
					                        callback?.Invoke(string.Join(".", statckPath), tbref, tbref.RefEntityType, stackValues);
 | 
				
			||||||
                        LocalNavigateReader(tbref.RefEntityType, propval);
 | 
					                        LocalNavigateReader(tbref.RefEntityType, propval);
 | 
				
			||||||
                        stackValues.RemoveAt(stackValues.Count - 1);
 | 
					                        stackValues.RemoveAt(stackValues.Count - 1);
 | 
				
			||||||
@@ -209,7 +212,7 @@ static class AggregateRootUtils
 | 
				
			|||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    case TableRefType.OneToMany:
 | 
					                    case TableRefType.OneToMany:
 | 
				
			||||||
                        var propvalOtm = table.GetPropertyValue(entity, prop.Name);
 | 
					                        var propvalOtm = table.GetPropertyValue(entity, prop.Name);
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entity, propvalOtm);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entity, propvalOtm);
 | 
				
			||||||
                        var propvalOtmList = new List<object>();
 | 
					                        var propvalOtmList = new List<object>();
 | 
				
			||||||
                        foreach (var val in propvalOtm as IEnumerable)
 | 
					                        foreach (var val in propvalOtm as IEnumerable)
 | 
				
			||||||
                            propvalOtmList.Add(val);
 | 
					                            propvalOtmList.Add(val);
 | 
				
			||||||
@@ -275,12 +278,12 @@ static class AggregateRootUtils
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    case TableRefType.OneToOne:
 | 
					                    case TableRefType.OneToOne:
 | 
				
			||||||
                        var propvalTo = tbref.RefEntityType.CreateInstanceGetDefaultValue();
 | 
					                        var propvalTo = tbref.RefEntityType.CreateInstanceGetDefaultValue();
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityFrom, propvalFrom);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom);
 | 
				
			||||||
                        LocalMapEntityValue(tbref.RefEntityType, propvalFrom, propvalTo);
 | 
					                        LocalMapEntityValue(tbref.RefEntityType, propvalFrom, propvalTo);
 | 
				
			||||||
                        EntityUtilExtensions.SetEntityValueWithPropertyName(fsql, entityType, entityTo, prop.Name, propvalTo);
 | 
					                        EntityUtilExtensions.SetEntityValueWithPropertyName(fsql, entityType, entityTo, prop.Name, propvalTo);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    case TableRefType.OneToMany:
 | 
					                    case TableRefType.OneToMany:
 | 
				
			||||||
                        SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityFrom, propvalFrom);
 | 
					                        SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom);
 | 
				
			||||||
                        LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, true);
 | 
					                        LocalMapEntityValueCollection(entityType, entityFrom, entityTo, tbref, propvalFrom as IEnumerable, prop, true);
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    case TableRefType.ManyToMany:
 | 
					                    case TableRefType.ManyToMany:
 | 
				
			||||||
@@ -315,6 +318,127 @@ static class AggregateRootUtils
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<ISelect0>>> _dicGetAutoIncludeQuery = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, Action<ISelect0>>>();
 | 
				
			||||||
 | 
					    public static ISelect<TEntity> GetAutoIncludeQuery<TEntity>(ISelect<TEntity> select)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var select0p = select as Select0Provider;
 | 
				
			||||||
 | 
					        var table0Type = select0p._tables[0].Table.Type;
 | 
				
			||||||
 | 
					        var func = _dicGetAutoIncludeQuery.GetOrAdd(typeof(TEntity), t => new ConcurrentDictionary<Type, Action<ISelect0>>()).GetOrAdd(table0Type, t =>
 | 
				
			||||||
 | 
					         {
 | 
				
			||||||
 | 
					             var parmExp1 = Expression.Parameter(typeof(ISelect0));
 | 
				
			||||||
 | 
					             var parmNavigateParameterExp = Expression.Parameter(typeof(TEntity), "a");
 | 
				
			||||||
 | 
					             var parmQueryExp = Expression.Convert(parmExp1, typeof(ISelect<>).MakeGenericType(typeof(TEntity)));
 | 
				
			||||||
 | 
					             var exp = LocalGetAutoIncludeQuery(parmQueryExp, 1, t, parmNavigateParameterExp, parmNavigateParameterExp, new Stack<Type>());
 | 
				
			||||||
 | 
					             return Expression.Lambda<Action<ISelect0>>(exp, parmExp1).Compile();
 | 
				
			||||||
 | 
					         });
 | 
				
			||||||
 | 
					        func(select);
 | 
				
			||||||
 | 
					        return select;
 | 
				
			||||||
 | 
					        Expression LocalGetAutoIncludeQuery(Expression queryExp, int depth, Type entityType, ParameterExpression navigateParameterExp, Expression navigatePathExp, Stack<Type> ignores)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (ignores.Any(a => a == entityType)) return queryExp;
 | 
				
			||||||
 | 
					            ignores.Push(entityType);
 | 
				
			||||||
 | 
					            var table = select0p._orm.CodeFirst.GetTableByEntity(entityType);
 | 
				
			||||||
 | 
					            if (table == null) return queryExp;
 | 
				
			||||||
 | 
					            foreach (var tr in table.GetAllTableRef())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var tbref = tr.Value;
 | 
				
			||||||
 | 
					                if (tbref.Exception != null) continue;
 | 
				
			||||||
 | 
					                if (table.Properties.TryGetValue(tr.Key, out var prop) == false) continue;
 | 
				
			||||||
 | 
					                Expression navigateExp = Expression.MakeMemberAccess(navigatePathExp, prop);
 | 
				
			||||||
 | 
					                //var lambdaAlias = (char)((byte)'a' + (depth - 1));
 | 
				
			||||||
 | 
					                switch (tbref.RefType)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case TableRefType.OneToOne:
 | 
				
			||||||
 | 
					                        if (ignores.Any(a => a == tbref.RefEntityType)) break;
 | 
				
			||||||
 | 
					                        LocalInclude(tbref, navigateExp);
 | 
				
			||||||
 | 
					                        queryExp = LocalGetAutoIncludeQuery(queryExp, depth, tbref.RefEntityType, navigateParameterExp, navigateExp, ignores);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.OneToMany:
 | 
				
			||||||
 | 
					                        LocalIncludeMany(tbref, navigateExp, true);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.ManyToMany:
 | 
				
			||||||
 | 
					                        LocalIncludeMany(tbref, navigateExp, false);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.PgArrayToMany:
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.ManyToOne: //不属于聚合根
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ignores.Pop();
 | 
				
			||||||
 | 
					            return queryExp;
 | 
				
			||||||
 | 
					            void LocalInclude(TableRef tbref, Expression exp)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var incMethod = queryExp.Type.GetMethod("Include");
 | 
				
			||||||
 | 
					                if (incMethod == null) throw new Exception(CoreStrings.RunTimeError_Reflection_IncludeMany.Replace("IncludeMany", "Include"));
 | 
				
			||||||
 | 
					                queryExp = Expression.Call(queryExp, incMethod.MakeGenericMethod(tbref.RefEntityType),
 | 
				
			||||||
 | 
					                    Expression.Lambda(typeof(Func<,>).MakeGenericType(entityType, tbref.RefEntityType), exp, navigateParameterExp));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            void LocalIncludeMany(TableRef tbref, Expression exp, bool isthen)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var funcType = typeof(Func<,>).MakeGenericType(entityType, typeof(IEnumerable<>).MakeGenericType(tbref.RefEntityType));
 | 
				
			||||||
 | 
					                var navigateSelector = Expression.Lambda(funcType, exp, navigateParameterExp);
 | 
				
			||||||
 | 
					                var incMethod = queryExp.Type.GetMethod("IncludeMany");
 | 
				
			||||||
 | 
					                if (incMethod == null) throw new Exception(CoreStrings.RunTimeError_Reflection_IncludeMany);
 | 
				
			||||||
 | 
					                LambdaExpression navigateThen = null;
 | 
				
			||||||
 | 
					                var navigateThenType = typeof(Action<>).MakeGenericType(typeof(ISelect<>).MakeGenericType(tbref.RefEntityType));
 | 
				
			||||||
 | 
					                var thenParameter = Expression.Parameter(typeof(ISelect<>).MakeGenericType(tbref.RefEntityType), "then");
 | 
				
			||||||
 | 
					                Expression paramQueryExp = thenParameter;
 | 
				
			||||||
 | 
					                var paramNavigateParameterExp = Expression.Parameter(tbref.RefEntityType, string.Concat((char)((byte)'a' + (depth - 1))));
 | 
				
			||||||
 | 
					                if (isthen) paramQueryExp = LocalGetAutoIncludeQuery(paramQueryExp, depth + 1, tbref.RefEntityType, paramNavigateParameterExp, paramNavigateParameterExp, ignores);
 | 
				
			||||||
 | 
					                navigateThen = Expression.Lambda(navigateThenType, paramQueryExp, thenParameter);
 | 
				
			||||||
 | 
					                queryExp = Expression.Call(queryExp, incMethod.MakeGenericMethod(tbref.RefEntityType), navigateSelector, navigateThen);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public static string GetAutoIncludeQueryStaicCode(IFreeSql fsql, Type rootEntityType)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return LocalGetAutoIncludeQueryStaicCode(1, rootEntityType, "", new Stack<Type>());
 | 
				
			||||||
 | 
					        string LocalGetAutoIncludeQueryStaicCode(int depth, Type entityType, string navigatePath, Stack<Type> ignores)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var code = new StringBuilder();
 | 
				
			||||||
 | 
					            if (ignores.Any(a => a == entityType)) return null;
 | 
				
			||||||
 | 
					            ignores.Push(entityType);
 | 
				
			||||||
 | 
					            var table = fsql.CodeFirst.GetTableByEntity(entityType);
 | 
				
			||||||
 | 
					            if (table == null) return null;
 | 
				
			||||||
 | 
					            if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}.";
 | 
				
			||||||
 | 
					            foreach (var tr in table.GetAllTableRef())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var tbref = tr.Value;
 | 
				
			||||||
 | 
					                if (tbref.Exception != null) continue;
 | 
				
			||||||
 | 
					                var navigateExpression = $"{navigatePath}{tr.Key}";
 | 
				
			||||||
 | 
					                var depthTab = "".PadLeft(depth * 4);
 | 
				
			||||||
 | 
					                var lambdaAlias = (char)((byte)'a' + (depth - 1));
 | 
				
			||||||
 | 
					                var lambdaStr = $"{lambdaAlias} => {lambdaAlias}.";
 | 
				
			||||||
 | 
					                switch (tbref.RefType)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case TableRefType.OneToOne:
 | 
				
			||||||
 | 
					                        if (ignores.Any(a => a == tbref.RefEntityType)) break;
 | 
				
			||||||
 | 
					                        code.Append("\r\n").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
				
			||||||
 | 
					                        code.Append(LocalGetAutoIncludeQueryStaicCode(depth, tbref.RefEntityType, navigateExpression, ignores));
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.OneToMany:
 | 
				
			||||||
 | 
					                        code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression);
 | 
				
			||||||
 | 
					                        var thencode = LocalGetAutoIncludeQueryStaicCode(depth + 1, tbref.RefEntityType, "", new Stack<Type>(ignores.ToArray()));
 | 
				
			||||||
 | 
					                        if (thencode.Length > 0) code.Append(", then => then").Append(thencode);
 | 
				
			||||||
 | 
					                        code.Append(")");
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.ManyToMany:
 | 
				
			||||||
 | 
					                        code.Append("\r\n").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.PgArrayToMany:
 | 
				
			||||||
 | 
					                        code.Append("\r\n//").Append(depthTab).Append(".IncludeMany(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case TableRefType.ManyToOne: //不属于聚合根
 | 
				
			||||||
 | 
					                        code.Append("\r\n//").Append(depthTab).Append(".Include(").Append(lambdaStr).Append(navigateExpression).Append(")");
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ignores.Pop();
 | 
				
			||||||
 | 
					            return code.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static List<object> GetManyToManyObjects(IFreeSql fsql, TableInfo table, TableRef tbref, object entity, PropertyInfo prop)
 | 
					    public static List<object> GetManyToManyObjects(IFreeSql fsql, TableInfo table, TableRef tbref, object entity, PropertyInfo prop)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (tbref.RefType != TableRefType.ManyToMany) return null;
 | 
					        if (tbref.RefType != TableRefType.ManyToMany) return null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,15 @@ namespace FreeSql.Tests.DbContext2
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                new OrderRepository(fsql, null);
 | 
					                new OrderRepository(fsql, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fsql.Insert(new[]
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new Tag { Name = "tag1" },
 | 
				
			||||||
 | 
					                    new Tag { Name = "tag2" },
 | 
				
			||||||
 | 
					                    new Tag { Name = "tag3" },
 | 
				
			||||||
 | 
					                    new Tag { Name = "tag4" },
 | 
				
			||||||
 | 
					                    new Tag { Name = "tag5" }
 | 
				
			||||||
 | 
					                }).ExecuteAffrows();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var repo = fsql.GetAggregateRootRepository<Order>();
 | 
					                var repo = fsql.GetAggregateRootRepository<Order>();
 | 
				
			||||||
                var order = new Order
 | 
					                var order = new Order
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -35,13 +44,37 @@ namespace FreeSql.Tests.DbContext2
 | 
				
			|||||||
                    Extdata = new OrderExt { Field3 = "field3" },
 | 
					                    Extdata = new OrderExt { Field3 = "field3" },
 | 
				
			||||||
                    Details = new List<OrderDetail>
 | 
					                    Details = new List<OrderDetail>
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        [0] = new OrderDetail { Field4 = "field4_01", Extdata = new OrderDetailExt { Field5 = "field5_01" } },
 | 
					                        new OrderDetail { Field4 = "field4_01", Extdata = new OrderDetailExt { Field5 = "field5_01" } },
 | 
				
			||||||
                        [0] = new OrderDetail { Field4 = "field4_02", Extdata = new OrderDetailExt { Field5 = "field5_02" } },
 | 
					                        new OrderDetail { Field4 = "field4_02", Extdata = new OrderDetailExt { Field5 = "field5_02" } },
 | 
				
			||||||
                        [0] = new OrderDetail { Field4 = "field4_03", Extdata = new OrderDetailExt { Field5 = "field5_03" } },
 | 
					                        new OrderDetail { Field4 = "field4_03", Extdata = new OrderDetailExt { Field5 = "field5_03" } },
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    Tags = fsql.Select<Tag>().Where(a => new[] { 1, 2, 3 }.Contains(a.Id)).ToList()
 | 
					                    Tags = fsql.Select<Tag>().Where(a => new[] { 1, 2, 3 }.Contains(a.Id)).ToList()
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                repo.Insert(order); //级联插入
 | 
					                repo.Insert(order); //级联插入
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var order2 = repo.Select.Where(a => a.Id == a.Id).First();
 | 
				
			||||||
 | 
					                Assert.NotNull(order2);
 | 
				
			||||||
 | 
					                Assert.Equal(order.Id, order2.Id);
 | 
				
			||||||
 | 
					                Assert.Equal(order.Field2, order2.Field2);
 | 
				
			||||||
 | 
					                Assert.NotNull(order2.Extdata);
 | 
				
			||||||
 | 
					                Assert.Equal(order.Extdata.Field3, order2.Extdata.Field3);
 | 
				
			||||||
 | 
					                Assert.NotNull(order2.Details);
 | 
				
			||||||
 | 
					                Assert.Equal(order.Details.Count, order2.Details.Count);
 | 
				
			||||||
 | 
					                Assert.Equal(3, order2.Details.Count);
 | 
				
			||||||
 | 
					                for (var a = 0; a < 3; a++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Assert.Equal(order.Details[a].Id, order2.Details[a].Id);
 | 
				
			||||||
 | 
					                    Assert.Equal(order.Details[a].OrderId, order2.Details[a].OrderId);
 | 
				
			||||||
 | 
					                    Assert.Equal(order.Details[a].Field4, order2.Details[a].Field4);
 | 
				
			||||||
 | 
					                    Assert.NotNull(order2.Details[a].Extdata);
 | 
				
			||||||
 | 
					                    Assert.Equal(order.Details[a].Extdata.Field5, order2.Details[a].Extdata.Field5);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Assert.NotNull(order2.Tags);
 | 
				
			||||||
 | 
					                Assert.Equal(3, order2.Tags.Count);
 | 
				
			||||||
 | 
					                Assert.Equal("tag1", order2.Tags[0].Name);
 | 
				
			||||||
 | 
					                Assert.Equal("tag2", order2.Tags[1].Name);
 | 
				
			||||||
 | 
					                Assert.Equal("tag3", order2.Tags[2].Name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        class Order
 | 
					        class Order
 | 
				
			||||||
@@ -103,7 +136,7 @@ namespace FreeSql.Tests.DbContext2
 | 
				
			|||||||
            public int Id { get; set; }
 | 
					            public int Id { get; set; }
 | 
				
			||||||
            public string Name { get; set; }
 | 
					            public string Name { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            [Navigate(ManyToMany = typeof(Order))]
 | 
					            [Navigate(ManyToMany = typeof(OrderTag))]
 | 
				
			||||||
            public List<Order> Orders { get; set; }
 | 
					            public List<Order> Orders { get; set; }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user