From 9180375a2b25b94033eafec7c14475b3a5cf3681 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Sat, 3 Sep 2022 16:27:14 +0800 Subject: [PATCH] AggregateRootRepository --- FreeSql.DbContext/FreeSql.DbContext.xml | 9 ++ FreeSql.Repository/AggregateRootRepository.cs | 122 +++++---------- FreeSql.Repository/AggregateRootUtils.cs | 140 +++++++++++++++++- .../AggregateRootRepositoryTest2.cs | 41 ++++- FreeSql/Extensions/EntityUtilExtensions.cs | 24 +-- 5 files changed, 226 insertions(+), 110 deletions(-) diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 537315e2..26522f10 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -800,5 +800,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.Repository/AggregateRootRepository.cs b/FreeSql.Repository/AggregateRootRepository.cs index 2b921ccb..c17d7c2a 100644 --- a/FreeSql.Repository/AggregateRootRepository.cs +++ b/FreeSql.Repository/AggregateRootRepository.cs @@ -1,16 +1,9 @@ using FreeSql.Extensions.EntityUtil; -using FreeSql.Internal; -using FreeSql.Internal.Model; using System; using System.Collections; -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; namespace FreeSql { @@ -156,7 +149,7 @@ namespace FreeSql get { var query = _repository.Select.TrackToList(SelectAggregateRootTracking); - SelectAggregateRootNavigateReader(query, EntityType, "", new Stack()); + query = AggregateRootUtils.GetAutoIncludeQuery(query); return query; } } @@ -166,7 +159,7 @@ namespace FreeSql /// 2、返回的内容用,可用于配合重写仓储 override Select 属性 /// 返回内容:fsql.Select<T>().Include(...).IncludeMany(...) /// - protected string SelectAggregateRootStaticCode => $"//fsql.Select<{EntityType.Name}>()\r\nthis.SelectDiy{SelectAggregateRootNavigateReader(1, EntityType, "", new Stack())}"; + protected string SelectAggregateRootStaticCode => $"//fsql.Select<{EntityType.Name}>()\r\nthis.SelectDiy{AggregateRootUtils.GetAutoIncludeQueryStaicCode(Orm, EntityType)}"; /// /// ISelect.TrackToList 委托,数据返回后自动 Attach /// @@ -198,83 +191,40 @@ namespace FreeSql return; } } - void SelectAggregateRootNavigateReader(ISelect currentQuery, Type entityType, string navigatePath, Stack ignores) - { - 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 tr in table.GetAllTableRef()) - { - var tbref = tr.Value; - if (tbref.Exception != null) continue; - var navigateExpression = $"{navigatePath}{tr.Key}"; - switch (tbref.RefType) - { - case TableRefType.OneToOne: - if (ignores.Any(a => a == tbref.RefEntityType)) break; - currentQuery.IncludeByPropertyName(navigateExpression); - SelectAggregateRootNavigateReader(currentQuery, tbref.RefEntityType, navigateExpression, ignores); - break; - case TableRefType.OneToMany: - var ignoresCopy = new Stack(ignores.ToArray()); - currentQuery.IncludeByPropertyName(navigateExpression, then => - SelectAggregateRootNavigateReader(then, tbref.RefEntityType, "", ignoresCopy)); - break; - case TableRefType.ManyToMany: - currentQuery.IncludeByPropertyName(navigateExpression); - break; - case TableRefType.PgArrayToMany: - case TableRefType.ManyToOne: //不属于聚合根 - break; - } - } - 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 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(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(); - } + //void SelectAggregateRootNavigateReader(ISelect currentQuery, Type entityType, string navigatePath, Stack ignores) + //{ + // 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 tr in table.GetAllTableRef()) + // { + // var tbref = tr.Value; + // if (tbref.Exception != null) continue; + // var navigateExpression = $"{navigatePath}{tr.Key}"; + // switch (tbref.RefType) + // { + // case TableRefType.OneToOne: + // if (ignores.Any(a => a == tbref.RefEntityType)) break; + // currentQuery.IncludeByPropertyName(navigateExpression); + // SelectAggregateRootNavigateReader(currentQuery, tbref.RefEntityType, navigateExpression, ignores); + // break; + // case TableRefType.OneToMany: + // var ignoresCopy = new Stack(ignores.ToArray()); + // currentQuery.IncludeByPropertyName(navigateExpression, then => + // SelectAggregateRootNavigateReader(then, tbref.RefEntityType, "", ignoresCopy)); //variable 'then' of type 'FreeSql.ISelect`1[System.Object]' referenced from scope '', but it is not defined + // break; + // case TableRefType.ManyToMany: + // currentQuery.IncludeByPropertyName(navigateExpression); + // break; + // case TableRefType.PgArrayToMany: + // case TableRefType.ManyToOne: //不属于聚合根 + // break; + // } + // } + // ignores.Pop(); + //} #endregion } diff --git a/FreeSql.Repository/AggregateRootUtils.cs b/FreeSql.Repository/AggregateRootUtils.cs index 16e83596..214c3a62 100644 --- a/FreeSql.Repository/AggregateRootUtils.cs +++ b/FreeSql.Repository/AggregateRootUtils.cs @@ -1,6 +1,7 @@ using FreeSql; using FreeSql.Extensions.EntityUtil; using FreeSql.Internal; +using FreeSql.Internal.CommonProvider; using FreeSql.Internal.Model; using System; using System.Collections; @@ -8,7 +9,9 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Linq.Expressions; using System.Reflection; +using System.Text; static class AggregateRootUtils { @@ -85,13 +88,13 @@ static class AggregateRootUtils switch (tbref.RefType) { case TableRefType.OneToOne: - SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityBefore, propvalBefore); - SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityAfter, propvalAfter); + SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore); + SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter); LocalCompareEntityValue(tbref.RefEntityType, propvalBefore, propvalAfter, null); break; case TableRefType.OneToMany: - SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityBefore, propvalBefore); - SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityAfter, propvalAfter); + SetNavigateRelationshipValue(fsql, tbref, table.Type, entityBefore, propvalBefore); + SetNavigateRelationshipValue(fsql, tbref, table.Type, entityAfter, propvalAfter); LocalCompareEntityValueCollection(tbref, propvalBefore as IEnumerable, propvalAfter as IEnumerable); break; case TableRefType.ManyToMany: @@ -201,7 +204,7 @@ static class AggregateRootUtils var propval = table.GetPropertyValue(entity, prop.Name); statckPath.Push(prop.Name); 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); LocalNavigateReader(tbref.RefEntityType, propval); stackValues.RemoveAt(stackValues.Count - 1); @@ -209,7 +212,7 @@ static class AggregateRootUtils break; case TableRefType.OneToMany: 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(); foreach (var val in propvalOtm as IEnumerable) propvalOtmList.Add(val); @@ -275,12 +278,12 @@ static class AggregateRootUtils { case TableRefType.OneToOne: var propvalTo = tbref.RefEntityType.CreateInstanceGetDefaultValue(); - SetNavigateRelationshipValue(fsql, tbref, tbref.RefEntityType, entityFrom, propvalFrom); + SetNavigateRelationshipValue(fsql, tbref, table.Type, entityFrom, propvalFrom); LocalMapEntityValue(tbref.RefEntityType, propvalFrom, propvalTo); EntityUtilExtensions.SetEntityValueWithPropertyName(fsql, entityType, entityTo, prop.Name, propvalTo); break; 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); break; case TableRefType.ManyToMany: @@ -315,6 +318,127 @@ static class AggregateRootUtils } } + static ConcurrentDictionary>> _dicGetAutoIncludeQuery = new ConcurrentDictionary>>(); + public static ISelect GetAutoIncludeQuery(ISelect select) + { + var select0p = select as Select0Provider; + var table0Type = select0p._tables[0].Table.Type; + var func = _dicGetAutoIncludeQuery.GetOrAdd(typeof(TEntity), t => new ConcurrentDictionary>()).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()); + return Expression.Lambda>(exp, parmExp1).Compile(); + }); + func(select); + return select; + Expression LocalGetAutoIncludeQuery(Expression queryExp, int depth, Type entityType, ParameterExpression navigateParameterExp, Expression navigatePathExp, Stack 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()); + string LocalGetAutoIncludeQueryStaicCode(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 = 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(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 GetManyToManyObjects(IFreeSql fsql, TableInfo table, TableRef tbref, object entity, PropertyInfo prop) { if (tbref.RefType != TableRefType.ManyToMany) return null; diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest2.cs b/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest2.cs index 81b76972..4540af13 100644 --- a/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest2.cs +++ b/FreeSql.Tests/FreeSql.Tests.DbContext2/AggregateRootRepositoryTest2.cs @@ -28,6 +28,15 @@ namespace FreeSql.Tests.DbContext2 { 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(); var order = new Order { @@ -35,13 +44,37 @@ namespace FreeSql.Tests.DbContext2 Extdata = new OrderExt { Field3 = "field3" }, Details = new List { - [0] = new OrderDetail { Field4 = "field4_01", Extdata = new OrderDetailExt { Field5 = "field5_01" } }, - [0] = 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_01", Extdata = new OrderDetailExt { Field5 = "field5_01" } }, + new OrderDetail { Field4 = "field4_02", Extdata = new OrderDetailExt { Field5 = "field5_02" } }, + new OrderDetail { Field4 = "field4_03", Extdata = new OrderDetailExt { Field5 = "field5_03" } }, }, Tags = fsql.Select().Where(a => new[] { 1, 2, 3 }.Contains(a.Id)).ToList() }; 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 @@ -103,7 +136,7 @@ namespace FreeSql.Tests.DbContext2 public int Id { get; set; } public string Name { get; set; } - [Navigate(ManyToMany = typeof(Order))] + [Navigate(ManyToMany = typeof(OrderTag))] public List Orders { get; set; } } } diff --git a/FreeSql/Extensions/EntityUtilExtensions.cs b/FreeSql/Extensions/EntityUtilExtensions.cs index 92a3ff54..e0d902fc 100644 --- a/FreeSql/Extensions/EntityUtilExtensions.cs +++ b/FreeSql/Extensions/EntityUtilExtensions.cs @@ -214,12 +214,12 @@ namespace FreeSql.Extensions.EntityUtil var var1Parm = Expression.Variable(entityType); var var2Ret = Expression.Variable(typeof(object)); var exps = new List(new Expression[] { - Expression.Assign(var1Parm, Expression.TypeAs(parm1, entityType)), - Expression.Assign( - var2Ret, - Expression.Convert(Expression.MakeMemberAccess(var1Parm, table.Properties[pn]), typeof(object)) - ) - }); + Expression.Assign(var1Parm, Expression.TypeAs(parm1, entityType)), + Expression.Assign( + var2Ret, + Expression.Convert(Expression.MakeMemberAccess(var1Parm, table.Properties[pn]), typeof(object)) + ) + }); exps.AddRange(new Expression[] { Expression.Return(returnTarget, var2Ret), Expression.Label(returnTarget, Expression.Default(typeof(object))) @@ -242,12 +242,12 @@ namespace FreeSql.Extensions.EntityUtil var var1Parm = Expression.Variable(table.Type); var var2Ret = Expression.Variable(typeof(object)); var exps = new List(new Expression[] { - Expression.Assign(var1Parm, Expression.TypeAs(parm1, table.Type)), - Expression.Assign( - var2Ret, - Expression.Convert(Expression.MakeMemberAccess(var1Parm, table.Properties[pn]), typeof(object)) - ) - }); + Expression.Assign(var1Parm, Expression.TypeAs(parm1, table.Type)), + Expression.Assign( + var2Ret, + Expression.Convert(Expression.MakeMemberAccess(var1Parm, table.Properties[pn]), typeof(object)) + ) + }); exps.AddRange(new Expression[] { Expression.Return(returnTarget, var2Ret), Expression.Label(returnTarget, Expression.Default(typeof(object)))