From 6703af3185b41924e44981cf7d837889044d0437 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Sat, 3 Sep 2022 11:53:01 +0800 Subject: [PATCH] AggregateRootRepository --- FreeSql.Repository/AggregateRootRepository.cs | 75 ++++++++++++++++++- .../AggregateRootRepositoryTest.cs | 12 +++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/FreeSql.Repository/AggregateRootRepository.cs b/FreeSql.Repository/AggregateRootRepository.cs index baecd9fd..80928cc0 100644 --- a/FreeSql.Repository/AggregateRootRepository.cs +++ b/FreeSql.Repository/AggregateRootRepository.cs @@ -7,6 +7,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -103,7 +104,7 @@ namespace FreeSql _childRepositorys.Clear(); } - #region State + #region 状态管理 protected Dictionary _states = new Dictionary(); protected class EntityState { @@ -135,8 +136,21 @@ namespace FreeSql } #endregion - #region Selectoriginal + #region 查询数据 + /// + /// 默认:创建查询对象(递归包含 Include/IncludeMany 边界之内的导航属性) + /// 重写:使用 + /// public virtual ISelect Select => SelectAggregateRoot; + /// + /// 创建查询对象(纯净) + /// 当聚合根内关系复杂时,使用 this.SelectAggregateRootStaticCode 可以生成边界以内的 Include/IncludeMany 代码块 + /// + protected ISelect SelectDiy => _repository.Select; + /// + /// 创建查询对象(递归包含 Include/IncludeMany 边界之内的导航属性) + /// + /// protected ISelect SelectAggregateRoot { get @@ -146,6 +160,17 @@ namespace FreeSql return query; } } + /// + /// 按默认边界规则,返回 c# 静态代码 + /// 1、聚合根内关系复杂手工编写 Include/IncludeMany 会很蛋疼 + /// 2、返回的内容用,可用于配合重写仓储 override Select 属性 + /// 返回内容:fsql.Select<T>().Include(...).IncludeMany(...) + /// + protected string SelectAggregateRootStaticCode => $"//fsql.Select<{EntityType.Name}>()\r\nthis.SelectDiy{SelectAggregateRootNavigateReader(1, EntityType, "", new Stack())}"; + /// + /// ISelect.TrackToList 委托,数据返回后自动 Attach + /// + /// protected void SelectAggregateRootTracking(object list) { if (list == null) return; @@ -178,11 +203,12 @@ namespace FreeSql if (ignores.Any(a => a == entityType)) return; ignores.Push(entityType); var table = Orm.CodeFirst.GetTableByEntity(entityType); + if (table == null) return; + if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}."; foreach (var prop in table.Properties.Values) { var tbref = table.GetTableRef(prop.Name, false); if (tbref == null) continue; - if (!string.IsNullOrWhiteSpace(navigatePath)) navigatePath = $"{navigatePath}."; var navigateExpression = $"{navigatePath}{prop.Name}"; switch (tbref.RefType) { @@ -206,6 +232,49 @@ namespace FreeSql } ignores.Pop(); } + string SelectAggregateRootNavigateReader(int depth, Type entityType, string navigatePath, Stack 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 prop in table.Properties.Values) + { + var tbref = table.GetTableRef(prop.Name, false); + if (tbref == null) continue; + var navigateExpression = $"{navigatePath}{prop.Name}"; + 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(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 } diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs b/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs index 46a233de..705d6b74 100644 --- a/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest.cs @@ -10,11 +10,23 @@ namespace FreeSql.Tests.DbContext2 { public class AggregateRootRepositoryTest { + class UserRepository : AggregateRootRepository + { + public UserRepository(IFreeSql fsql, UnitOfWorkManager uowManager) : base(uowManager?.Orm ?? fsql) + { + var code = SelectAggregateRootStaticCode; + } + + public override ISelect Select => base.SelectDiy; + } + [Fact] public void Test1v1() { using (var fsql = g.CreateMemory()) { + new UserRepository(fsql, null); + var repo = fsql.GetAggregateRootRepository(); var user = new User {