- 修复 多对多导航属性 AsSelect() 无法使用 .Count() 的问题;#362

This commit is contained in:
28810 2020-07-06 16:10:36 +08:00
parent 1caaba4005
commit bc77869cf7
4 changed files with 49 additions and 9 deletions

View File

@ -486,5 +486,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>

View File

@ -111,6 +111,12 @@ namespace FreeSql.Tests.SqlServer
// WHERE(t.[Name] = '国语') AND(t.[Id] = Mt_Ms.[Tag_id]) // WHERE(t.[Name] = '国语') AND(t.[Id] = Mt_Ms.[Tag_id])
// limit 0, 1)) // limit 0, 1))
// limit 0, 1)) // limit 0, 1))
var t3 = g.sqlserver.Select<Song>().ToList(r => new
{
r.Title,
count = r.Tags.AsSelect().Count()
});
} }
[Fact] [Fact]

View File

@ -107,6 +107,17 @@ namespace FreeSql.Tests.Sqlite
// WHERE(t.`Name` = '国语') AND(t.`Id` = Mt_Ms.`Tag_id`) // WHERE(t.`Name` = '国语') AND(t.`Id` = Mt_Ms.`Tag_id`)
// limit 0, 1)) // limit 0, 1))
// limit 0, 1)) // limit 0, 1))
var t3 = g.sqlite.Select<Song>().ToList(r => new
{
r.Title,
count = r.Tags.AsSelect().Count(),
//sum = r.Tags.AsSelect().Sum(b => b.Id + 0),
//avg = r.Tags.AsSelect().Avg(b => b.Id + 1),
//max = r.Tags.AsSelect().Max(b => b.Id + 2),
//min = r.Tags.AsSelect().Min(b => b.Id + 3),
//first = r.Tags.AsSelect().First(b => b.Name)
});
} }
[Fact] [Fact]

View File

@ -426,7 +426,7 @@ namespace FreeSql.Internal
static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectMethodInfo = new ConcurrentDictionary<Type, MethodInfo>(); static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereMethodInfo = new ConcurrentDictionary<Type, MethodInfo>(); static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo = new ConcurrentDictionary<Type, MethodInfo>(); static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo = new ConcurrentDictionary<Type, MethodInfo>();
static ConcurrentDictionary<Type, MethodInfo> _dicExpressionLambdaToSqlAsSelectAnyMethodInfo = new ConcurrentDictionary<Type, MethodInfo>(); static ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>> _dicExpressionLambdaToSqlAsSelectAggMethodInfo = new ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>>();
internal static ConcurrentDictionary<Type, PropertyInfo> _dicNullableValueProperty = new ConcurrentDictionary<Type, PropertyInfo>(); internal static ConcurrentDictionary<Type, PropertyInfo> _dicNullableValueProperty = new ConcurrentDictionary<Type, PropertyInfo>();
static ConcurrentDictionary<Type, Expression> _dicFreeSqlGlobalExtensionsAsSelectExpression = new ConcurrentDictionary<Type, Expression>(); static ConcurrentDictionary<Type, Expression> _dicFreeSqlGlobalExtensionsAsSelectExpression = new ConcurrentDictionary<Type, Expression>();
static MethodInfo MethodDateTimeSubtractDateTime = typeof(DateTime).GetMethod("Subtract", new Type[] { typeof(DateTime) }); static MethodInfo MethodDateTimeSubtractDateTime = typeof(DateTime).GetMethod("Subtract", new Type[] { typeof(DateTime) });
@ -915,8 +915,8 @@ namespace FreeSql.Internal
} }
var fsqlWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(asSelectEntityType, asSelectEntityType3 => var fsqlWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(asSelectEntityType, asSelectEntityType3 =>
typeof(ISelect<>).MakeGenericType(asSelectEntityType3).GetMethod("Where", new[] { typeof(ISelect<>).MakeGenericType(asSelectEntityType3).GetMethod("Where", new[] {
typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(asSelectEntityType3, typeof(bool))) typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(asSelectEntityType3, typeof(bool)))
})); }));
var parm123Tb = _common.GetTableByEntity(asSelectParentExp.Type); var parm123Tb = _common.GetTableByEntity(asSelectParentExp.Type);
var parm123Ref = parm123Tb.GetTableRef(asSelectParentExp1.Member.Name, true); var parm123Ref = parm123Tb.GetTableRef(asSelectParentExp1.Member.Name, true);
if (parm123Ref != null) if (parm123Ref != null)
@ -929,12 +929,10 @@ namespace FreeSql.Internal
var manyTb = _common.GetTableByEntity(parm123Ref.RefMiddleEntityType); var manyTb = _common.GetTableByEntity(parm123Ref.RefMiddleEntityType);
var manySubSelectWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 => var manySubSelectWhere = _dicExpressionLambdaToSqlAsSelectWhereMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
typeof(ISelect<>).MakeGenericType(refMiddleEntityType3).GetMethod("Where", new[] { typeof(ISelect<>).MakeGenericType(refMiddleEntityType3).GetMethod("Where", new[] {
typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(refMiddleEntityType3, typeof(bool))) typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(refMiddleEntityType3, typeof(bool)))
})); }));
var manySubSelectWhereSql = _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 => var manySubSelectWhereSql = _dicExpressionLambdaToSqlAsSelectWhereSqlMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(refMiddleEntityType3), refMiddleEntityType3).GetMethod("Where", new[] { typeof(string), typeof(object) })); typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(refMiddleEntityType3), refMiddleEntityType3).GetMethod("Where", new[] { typeof(string), typeof(object) }));
var manySubSelectAny = _dicExpressionLambdaToSqlAsSelectAnyMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(refMiddleEntityType3), refMiddleEntityType3).GetMethod("Any", new Type[0]));
var manySubSelectAsSelectExp = _dicFreeSqlGlobalExtensionsAsSelectExpression.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 => var manySubSelectAsSelectExp = _dicFreeSqlGlobalExtensionsAsSelectExpression.GetOrAdd(parm123Ref.RefMiddleEntityType, refMiddleEntityType3 =>
Expression.Call( Expression.Call(
typeof(FreeSqlGlobalExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(mfil => mfil.Name == "AsSelect" && mfil.GetParameters().Length == 1).FirstOrDefault()?.MakeGenericMethod(refMiddleEntityType3), typeof(FreeSqlGlobalExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(mfil => mfil.Name == "AsSelect" && mfil.GetParameters().Length == 1).FirstOrDefault()?.MakeGenericMethod(refMiddleEntityType3),
@ -987,9 +985,25 @@ namespace FreeSql.Internal
var sql2 = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { "1" })?.ToString(); var sql2 = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { "1" })?.ToString();
if (string.IsNullOrEmpty(sql2) == false) if (string.IsNullOrEmpty(sql2) == false)
manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectWhereSql, Expression.Constant($"exists({sql2.Replace("\r\n", "\r\n\t")})"), Expression.Constant(null)); manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectWhereSql, Expression.Constant($"exists({sql2.Replace("\r\n", "\r\n\t")})"), Expression.Constant(null));
manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectAny); MethodInfo manySubSelectAggMethod = null;
switch (exp3.Method.Name) //https://github.com/dotnetcore/FreeSql/issues/362
{
case "Any":
case "Count":
manySubSelectAggMethod = _dicExpressionLambdaToSqlAsSelectAggMethodInfo.GetOrAdd(parm123Ref.RefMiddleEntityType, _ => new ConcurrentDictionary<string, MethodInfo>()).GetOrAdd(exp3.Method.Name, exp3MethodName =>
typeof(ISelect0<,>).MakeGenericType(typeof(ISelect<>).MakeGenericType(parm123Ref.RefMiddleEntityType), parm123Ref.RefMiddleEntityType).GetMethod(exp3MethodName, new Type[0]));
manySubSelectExpBoy = Expression.Call(manySubSelectExpBoy, manySubSelectAggMethod);
break;
case "Sum":
case "Min":
case "Max":
case "Avg":
case "ToList":
case "ToOne":
case "First":
throw new ArgumentException($"ManyToMany 导航属性 .AsSelect() 暂时不可用于 Sum/Avg/Max/Min/First/ToOne/ToList 方法");
}
asSelectBefores.Clear(); asSelectBefores.Clear();
return ExpressionLambdaToSql(manySubSelectExpBoy, tsc); return ExpressionLambdaToSql(manySubSelectExpBoy, tsc);
} }
for (var mn = 0; mn < parm123Ref.Columns.Count; mn++) for (var mn = 0; mn < parm123Ref.Columns.Count; mn++)