mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-19 12:28:15 +08:00
- 补充 实现表达式转换类型的解析,如:Select<object>().Where(a => (a as 实体类型).Id == 0);
- 完善 ExpressionTree 基础数据类型 TryParse 使用与单元测试; - 优化 ManyToMany 中间实体未配置主键时,自动配置联合主键; - 修复 Expression.And 的使用问题;
This commit is contained in:
@ -140,6 +140,43 @@ namespace FreeSql.Extensions.EntityUtil {
|
||||
});
|
||||
return func(entity);
|
||||
}
|
||||
static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, ConcurrentDictionary<string, Func<object, object>>>> _dicGetEntityValueWithPropertyName = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, ConcurrentDictionary<string, Func<object, object>>>>();
|
||||
/// <summary>
|
||||
/// 获取实体的属性值
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="_table"></param>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
//public static object GetEntityValueWithPropertyName<TEntity>(this IFreeSql orm, TEntity entity, string propertyName) => GetEntityKeyValues(orm, typeof(TEntity), entity, propertyName);
|
||||
public static object GetEntityValueWithPropertyName(this IFreeSql orm, Type entityType, object entity, string propertyName) {
|
||||
if (entity == null) return null;
|
||||
if (entityType == null) entityType = entity.GetType();
|
||||
var func = _dicGetEntityValueWithPropertyName
|
||||
.GetOrAdd(orm.Ado.DataType, dt => new ConcurrentDictionary<Type, ConcurrentDictionary<string, Func<object, object>>>())
|
||||
.GetOrAdd(entityType, et => new ConcurrentDictionary<string, Func<object, object>>())
|
||||
.GetOrAdd(propertyName, pn => {
|
||||
var _table = orm.CodeFirst.GetTableByEntity(entityType);
|
||||
var pks = _table.Primarys;
|
||||
var returnTarget = Expression.Label(typeof(object));
|
||||
var parm1 = Expression.Parameter(typeof(object));
|
||||
var var1Parm = Expression.Variable(entityType);
|
||||
var var2Ret = Expression.Variable(typeof(object));
|
||||
var exps = new List<Expression>(new Expression[] {
|
||||
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)))
|
||||
});
|
||||
return Expression.Lambda<Func<object, object>>(Expression.Block(new[] { var1Parm, var2Ret }, exps), new[] { parm1 }).Compile();
|
||||
});
|
||||
return func(entity);
|
||||
}
|
||||
static ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Func<object, string>>> _dicGetEntityString = new ConcurrentDictionary<DataType, ConcurrentDictionary<Type, Func<object, string>>>();
|
||||
/// <summary>
|
||||
/// 获取实体的所有数据,以 (1, 2, xxx) 的形式
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Version>0.5.1</Version>
|
||||
<Version>0.5.1.1</Version>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>YeXiangQin</Authors>
|
||||
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
|
||||
|
@ -311,6 +311,7 @@ namespace FreeSql.Internal {
|
||||
case ExpressionType.Not: return $"not({ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName, isDisableDiyParse, style)})";
|
||||
case ExpressionType.Quote: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName, isDisableDiyParse, style);
|
||||
case ExpressionType.Lambda: return ExpressionLambdaToSql((exp as LambdaExpression)?.Body, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName, isDisableDiyParse, style);
|
||||
case ExpressionType.TypeAs:
|
||||
case ExpressionType.Convert:
|
||||
//var othercExp = ExpressionLambdaToSqlOther(exp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName, isDisableDiyParse, style);
|
||||
//if (string.IsNullOrEmpty(othercExp) == false) return othercExp;
|
||||
@ -487,7 +488,7 @@ namespace FreeSql.Internal {
|
||||
}
|
||||
var tmpExp = Expression.Equal(pexp1, pexp2);
|
||||
if (mn == 0) manySubSelectWhereExp = tmpExp;
|
||||
else manySubSelectWhereExp = Expression.And(manySubSelectWhereExp, tmpExp);
|
||||
else manySubSelectWhereExp = Expression.AndAlso(manySubSelectWhereExp, tmpExp);
|
||||
}
|
||||
var manySubSelectExpBoy = Expression.Call(
|
||||
manySubSelectAsSelectExp,
|
||||
@ -509,7 +510,7 @@ namespace FreeSql.Internal {
|
||||
}
|
||||
var tmpExp = Expression.Equal(pexp1, pexp2);
|
||||
if (mn == 0) fsqlManyWhereExp = tmpExp;
|
||||
else fsqlManyWhereExp = Expression.And(fsqlManyWhereExp, tmpExp);
|
||||
else fsqlManyWhereExp = Expression.AndAlso(fsqlManyWhereExp, tmpExp);
|
||||
}
|
||||
fsqltables.Add(new SelectTableInfo { Alias = manySubSelectWhereParam.Name, Parameter = manySubSelectWhereParam, Table = manyTb, Type = SelectTableInfoType.Parent });
|
||||
fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlManyWhereExp, fsqlWhereParam) });
|
||||
@ -532,7 +533,7 @@ namespace FreeSql.Internal {
|
||||
}
|
||||
var tmpExp = Expression.Equal(pexp1, pexp2);
|
||||
if (mn == 0) fsqlWhereExp = tmpExp;
|
||||
else fsqlWhereExp = Expression.And(fsqlWhereExp, tmpExp);
|
||||
else fsqlWhereExp = Expression.AndAlso(fsqlWhereExp, tmpExp);
|
||||
}
|
||||
fsqlWhere.Invoke(fsql, new object[] { Expression.Lambda(fsqlWhereExp, fsqlWhereParam) });
|
||||
}
|
||||
@ -592,6 +593,15 @@ namespace FreeSql.Internal {
|
||||
exp2 = callExp.Object;
|
||||
if (exp2 == null) break;
|
||||
continue;
|
||||
case ExpressionType.TypeAs:
|
||||
case ExpressionType.Convert:
|
||||
var oper2 = (exp2 as UnaryExpression).Operand;
|
||||
if (oper2.NodeType == ExpressionType.Parameter) {
|
||||
var oper2Parm = oper2 as ParameterExpression;
|
||||
expStack.Push(Expression.Parameter(exp2.Type, oper2Parm.Name));
|
||||
} else
|
||||
expStack.Push(oper2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -681,7 +691,7 @@ namespace FreeSql.Internal {
|
||||
}
|
||||
var tmpExp = Expression.Equal(pexp1, pexp2);
|
||||
if (mn == 0) navCondExp = tmpExp;
|
||||
else navCondExp = Expression.And(navCondExp, tmpExp);
|
||||
else navCondExp = Expression.AndAlso(navCondExp, tmpExp);
|
||||
}
|
||||
if (find.Type == SelectTableInfoType.InnerJoin ||
|
||||
find.Type == SelectTableInfoType.LeftJoin ||
|
||||
|
@ -343,6 +343,8 @@ namespace FreeSql.Internal {
|
||||
|
||||
nvref.Columns.Add(trytb.Primarys[a]);
|
||||
nvref.MiddleColumns.Add(trycol);
|
||||
if (tbmid.Primarys.Any() == false)
|
||||
trycol.Attribute.IsPrimary = true;
|
||||
|
||||
if (isLazy) {
|
||||
if (a > 0) lmbdWhere.Append(" && ");
|
||||
@ -374,6 +376,8 @@ namespace FreeSql.Internal {
|
||||
|
||||
nvref.RefColumns.Add(tbref.Primarys[a]);
|
||||
nvref.MiddleColumns.Add(trycol);
|
||||
if (tbmid.Primarys.Any() == false)
|
||||
trycol.Attribute.IsPrimary = true;
|
||||
|
||||
if (isLazy) lmbdWhere.Append(" && b.").Append(trycol.CsName).Append(" == a.").Append(tbref.Primarys[a].CsName);
|
||||
}
|
||||
@ -382,6 +386,9 @@ namespace FreeSql.Internal {
|
||||
nvref.RefEntityType = tbref.Type;
|
||||
nvref.RefType = TableRefType.ManyToMany;
|
||||
trytb.AddOrUpdateTableRef(pnv.Name, nvref);
|
||||
|
||||
if (tbmid.Primarys.Any() == false)
|
||||
tbmid.Primarys = tbmid.Columns.Values.Where(a => a.Attribute.IsPrimary == true).ToArray();
|
||||
}
|
||||
|
||||
if (isLazy) {
|
||||
@ -819,7 +826,7 @@ namespace FreeSql.Internal {
|
||||
if (typetb.ColumnsByCs.TryGetValue(ctorParm.Name, out var trycol) && trycol.Attribute.IsPrimary) {
|
||||
ispkExp.Add(
|
||||
Expression.IfThen(
|
||||
Expression.And(
|
||||
Expression.AndAlso(
|
||||
Expression.IsFalse(readpknullExp),
|
||||
Expression.Or(
|
||||
Expression.Equal(readpkvalExp, Expression.Constant(DBNull.Value)),
|
||||
@ -905,7 +912,7 @@ namespace FreeSql.Internal {
|
||||
if (typetb.ColumnsByCs.TryGetValue(prop.Name, out var trycol) && trycol.Attribute.IsPrimary) {
|
||||
ispkExp.Add(
|
||||
Expression.IfThen(
|
||||
Expression.And(
|
||||
Expression.AndAlso(
|
||||
Expression.IsFalse(readpknullExp),
|
||||
Expression.Or(
|
||||
Expression.Equal(readpkvalExp, Expression.Constant(DBNull.Value)),
|
||||
@ -1000,7 +1007,7 @@ namespace FreeSql.Internal {
|
||||
static MethodInfo MethodArrayGetValue = typeof(Array).GetMethod("GetValue", new[] { typeof(int) });
|
||||
static MethodInfo MethodArrayGetLength = typeof(Array).GetMethod("GetLength", new[] { typeof(int) });
|
||||
static MethodInfo MethodMygisGeometryParse = typeof(MygisGeometry).GetMethod("Parse", new[] { typeof(string) });
|
||||
static MethodInfo MethodGuidParse = typeof(Guid).GetMethod("Parse", new[] { typeof(string) });
|
||||
static MethodInfo MethodGuidTryParse = typeof(Guid).GetMethod("TryParse", new[] { typeof(string), typeof(Guid).MakeByRefType() });
|
||||
static MethodInfo MethodEnumParse = typeof(Enum).GetMethod("Parse", new[] { typeof(Type), typeof(string), typeof(bool) });
|
||||
static MethodInfo MethodToString = typeof(string).GetMethod("Concat", new[] { typeof(object) });
|
||||
static MethodInfo MethodConvertChangeType = typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) });
|
||||
@ -1020,6 +1027,8 @@ namespace FreeSql.Internal {
|
||||
static MethodInfo MethodDoubleTryParse = typeof(double).GetMethod("TryParse", new[] { typeof(string), typeof(double).MakeByRefType() });
|
||||
static MethodInfo MethodFloatTryParse = typeof(float).GetMethod("TryParse", new[] { typeof(string), typeof(float).MakeByRefType() });
|
||||
static MethodInfo MethodDecimalTryParse = typeof(decimal).GetMethod("TryParse", new[] { typeof(string), typeof(decimal).MakeByRefType() });
|
||||
static MethodInfo MethodDateTimeTryParse = typeof(DateTime).GetMethod("TryParse", new[] { typeof(string), typeof(DateTime).MakeByRefType() });
|
||||
static MethodInfo MethodDateTimeOffsetTryParse = typeof(DateTimeOffset).GetMethod("TryParse", new[] { typeof(string), typeof(DateTimeOffset).MakeByRefType() });
|
||||
public static Expression GetDataReaderValueBlockExpression(Type type, Expression value) {
|
||||
var returnTarget = Expression.Label(typeof(object));
|
||||
var valueExp = Expression.Variable(typeof(object), "locvalue");
|
||||
@ -1070,11 +1079,22 @@ namespace FreeSql.Internal {
|
||||
ParameterExpression tryparseVarExp = null;
|
||||
switch (type.FullName) {
|
||||
case "System.Guid":
|
||||
return Expression.IfThenElse(
|
||||
Expression.TypeEqual(valueExp, type),
|
||||
Expression.Return(returnTarget, valueExp),
|
||||
Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodGuidParse, Expression.Convert(valueExp, typeof(string))), typeof(object)))
|
||||
);
|
||||
//return Expression.IfThenElse(
|
||||
// Expression.TypeEqual(valueExp, type),
|
||||
// Expression.Return(returnTarget, valueExp),
|
||||
// Expression.Return(returnTarget, Expression.Convert(Expression.Call(MethodGuidParse, Expression.Convert(valueExp, typeof(string))), typeof(object)))
|
||||
//);
|
||||
tryparseExp = Expression.Block(
|
||||
new[] { tryparseVarExp = Expression.Variable(typeof(Guid)) },
|
||||
new Expression[] {
|
||||
Expression.IfThenElse(
|
||||
Expression.IsTrue(Expression.Call(MethodGuidTryParse, Expression.Convert(valueExp, typeof(string)), tryparseVarExp)),
|
||||
Expression.Return(returnTarget, Expression.Convert(tryparseVarExp, typeof(object))),
|
||||
Expression.Return(returnTarget, Expression.Convert(Expression.Default(typeOrg), typeof(object)))
|
||||
)
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "MygisPoint": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisPoint)));
|
||||
case "MygisLineString": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisLineString)));
|
||||
case "MygisPolygon": return Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodMygisGeometryParse, Expression.Convert(valueExp, typeof(string))), typeof(MygisPolygon)));
|
||||
@ -1223,6 +1243,30 @@ namespace FreeSql.Internal {
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "System.DateTime":
|
||||
tryparseExp = Expression.Block(
|
||||
new[] { tryparseVarExp = Expression.Variable(typeof(DateTime)) },
|
||||
new Expression[] {
|
||||
Expression.IfThenElse(
|
||||
Expression.IsTrue(Expression.Call(MethodDateTimeTryParse, Expression.Convert(valueExp, typeof(string)), tryparseVarExp)),
|
||||
Expression.Return(returnTarget, Expression.Convert(tryparseVarExp, typeof(object))),
|
||||
Expression.Return(returnTarget, Expression.Convert(Expression.Default(typeOrg), typeof(object)))
|
||||
)
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "System.DateTimeOffset":
|
||||
tryparseExp = Expression.Block(
|
||||
new[] { tryparseVarExp = Expression.Variable(typeof(DateTimeOffset)) },
|
||||
new Expression[] {
|
||||
Expression.IfThenElse(
|
||||
Expression.IsTrue(Expression.Call(MethodDateTimeOffsetTryParse, Expression.Convert(valueExp, typeof(string)), tryparseVarExp)),
|
||||
Expression.Return(returnTarget, Expression.Convert(tryparseVarExp, typeof(object))),
|
||||
Expression.Return(returnTarget, Expression.Convert(Expression.Default(typeOrg), typeof(object)))
|
||||
)
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "System.Boolean":
|
||||
tryparseBooleanExp = Expression.Return(returnTarget,
|
||||
Expression.Convert(
|
||||
@ -1241,9 +1285,12 @@ namespace FreeSql.Internal {
|
||||
switchExp = Expression.Switch(
|
||||
Expression.Constant(type),
|
||||
Expression.SwitchCase(tryparseExp,
|
||||
Expression.Constant(typeof(Guid)),
|
||||
Expression.Constant(typeof(sbyte)), Expression.Constant(typeof(short)), Expression.Constant(typeof(int)), Expression.Constant(typeof(long)),
|
||||
Expression.Constant(typeof(byte)), Expression.Constant(typeof(ushort)), Expression.Constant(typeof(uint)), Expression.Constant(typeof(ulong)),
|
||||
Expression.Constant(typeof(double)), Expression.Constant(typeof(float)), Expression.Constant(typeof(decimal))),
|
||||
Expression.Constant(typeof(double)), Expression.Constant(typeof(float)), Expression.Constant(typeof(decimal)),
|
||||
Expression.Constant(typeof(DateTime)), Expression.Constant(typeof(DateTimeOffset))
|
||||
),
|
||||
Expression.SwitchCase(Expression.Return(returnTarget, Expression.Call(MethodConvertChangeType, valueExp, Expression.Constant(type, typeof(Type)))), Expression.Constant(type))
|
||||
);
|
||||
else if (tryparseBooleanExp != null)
|
||||
|
Reference in New Issue
Block a user