mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	- 增加 ExpressionCallAttribute 特性,实现表达式函数自定义解析;
This commit is contained in:
		@@ -10,6 +10,7 @@ using Npgsql.LegacyPostgis;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Tests
 | 
			
		||||
{
 | 
			
		||||
@@ -167,6 +168,34 @@ namespace FreeSql.Tests
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Test02()
 | 
			
		||||
        {
 | 
			
		||||
            g.mysql.Aop.ParseExpression = (s, e) =>
 | 
			
		||||
            {
 | 
			
		||||
                if (e.Expression.NodeType == ExpressionType.Call)
 | 
			
		||||
                {
 | 
			
		||||
                    var callExp = e.Expression as MethodCallExpression;
 | 
			
		||||
                    if (callExp.Object?.Type == typeof(DateTime) &&
 | 
			
		||||
                        callExp.Method.Name == "ToString" &&
 | 
			
		||||
                        callExp.Arguments.Count == 1 &&
 | 
			
		||||
                        callExp.Arguments[0].Type == typeof(string) &&
 | 
			
		||||
                        callExp.Arguments[0].NodeType == ExpressionType.Constant)
 | 
			
		||||
                    {
 | 
			
		||||
                        var format = (callExp.Arguments[0] as ConstantExpression)?.Value?.ToString();
 | 
			
		||||
 | 
			
		||||
                        if (string.IsNullOrEmpty(format) == false)
 | 
			
		||||
                        {
 | 
			
		||||
                            var tmp = e.FreeParse(callExp.Object);
 | 
			
		||||
 | 
			
		||||
                            switch (format)
 | 
			
		||||
                            {
 | 
			
		||||
                                case "yyyy-MM-dd HH:mm":
 | 
			
		||||
                                    tmp = $"date_format({tmp}, '%Y-%m-%d %H:%i')";
 | 
			
		||||
                                    break;
 | 
			
		||||
                            }
 | 
			
		||||
                            e.Result = tmp;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var dbs = g.sqlserver.DbFirst.GetDatabases();
 | 
			
		||||
@@ -233,6 +262,21 @@ namespace FreeSql.Tests
 | 
			
		||||
                .IncludeMany(m => m.Permissions.Where(p => p.SysModuleId == m.Id),
 | 
			
		||||
                    then => then.LeftJoin(p => p.Button.Id == p.SysModuleButtonId))
 | 
			
		||||
                .ToList();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var sql = g.sqlite.Select<SysModule>()
 | 
			
		||||
                .ToSql(a => a.CreateTime.FormatDateTime("yyyy-MM-dd"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [ExpressionCall]
 | 
			
		||||
    public static class DbFunc
 | 
			
		||||
    {
 | 
			
		||||
        static ThreadLocal<ExpressionCallContext> context = new ThreadLocal<ExpressionCallContext>();
 | 
			
		||||
 | 
			
		||||
        public static string FormatDateTime(this DateTime that, string arg1)
 | 
			
		||||
        {
 | 
			
		||||
            return $"date_format({context.Value.Values["arg1"]})";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								FreeSql/DataAnnotations/ExpressionCallAttribute.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								FreeSql/DataAnnotations/ExpressionCallAttribute.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.DataAnnotations
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 自定义表达式函数解析<para></para>
 | 
			
		||||
    /// 注意:请使用静态扩展类
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Class)]
 | 
			
		||||
    public class ExpressionCallAttribute : Attribute
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ExpressionCallContext
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 数据库类型,可用于适配多种数据库环境
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public DataType DataType { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// 已解析的表达式中参数内容
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public Dictionary<string, string> Values { get; } = new Dictionary<string, string>();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -44,6 +44,16 @@ public static partial class FreeSqlGlobalExtensions
 | 
			
		||||
    public static bool IsArrayOrList(this Type that) => that == null ? false : (that.IsArray || typeof(IList).IsAssignableFrom(that));
 | 
			
		||||
    public static Type NullableTypeOrThis(this Type that) => that?.IsNullableType() == true ? that.GetGenericArguments().First() : that;
 | 
			
		||||
    internal static string NotNullAndConcat(this string that, params object[] args) => string.IsNullOrEmpty(that) ? null : string.Concat(new object[] { that }.Concat(args));
 | 
			
		||||
    static ConcurrentDictionary<Type, ParameterInfo[]> _dicGetDefaultValueFirstConstructorsParameters = new ConcurrentDictionary<Type, ParameterInfo[]>();
 | 
			
		||||
    public static object CreateInstanceGetDefaultValue(this Type that)
 | 
			
		||||
    {
 | 
			
		||||
        if (that == null) return null;
 | 
			
		||||
        if (that == typeof(string)) return default(string);
 | 
			
		||||
        if (that.IsArray) return Array.CreateInstance(that, 0);
 | 
			
		||||
        var ctorParms = _dicGetDefaultValueFirstConstructorsParameters.GetOrAdd(that, tp => tp.GetConstructors().FirstOrDefault()?.GetParameters());
 | 
			
		||||
        if (ctorParms == null || ctorParms.Any() == false) return Activator.CreateInstance(that, null);
 | 
			
		||||
        return Activator.CreateInstance(that, ctorParms.Select(a => Activator.CreateInstance(a.ParameterType, null)).ToArray());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>> _dicGetPropertiesDictIgnoreCase = new ConcurrentDictionary<Type, Dictionary<string, PropertyInfo>>();
 | 
			
		||||
    public static Dictionary<string, PropertyInfo> GetPropertiesDictIgnoreCase(this Type that) => that == null ? null : _dicGetPropertiesDictIgnoreCase.GetOrAdd(that, tp =>
 | 
			
		||||
 
 | 
			
		||||
@@ -152,6 +152,22 @@
 | 
			
		||||
            <param name="value"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="T:FreeSql.DataAnnotations.ExpressionCallAttribute">
 | 
			
		||||
            <summary>
 | 
			
		||||
            自定义表达式函数解析<para></para>
 | 
			
		||||
            注意:请使用静态扩展类
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:FreeSql.DataAnnotations.ExpressionCallContext.DataType">
 | 
			
		||||
            <summary>
 | 
			
		||||
            数据库类型,可用于适配多种数据库环境
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:FreeSql.DataAnnotations.ExpressionCallContext.Values">
 | 
			
		||||
            <summary>
 | 
			
		||||
            已解析的表达式中参数内容
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:FreeSql.DataAnnotations.IndexAttribute.Name">
 | 
			
		||||
            <summary>
 | 
			
		||||
            索引名
 | 
			
		||||
@@ -2000,6 +2016,137 @@
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="readerHander"></param>
 | 
			
		||||
            <param name="cmdType"></param>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            在【主库】执行
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdType"></param>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            在【主库】执行
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdType"></param>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.QueryAsync``1(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T"></typeparam>
 | 
			
		||||
            <param name="cmdType"></param>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.QueryAsync``1(System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T"></typeparam>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.QueryAsync``2(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="cmdType"></param>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="cmdParms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeSql.IAdo.QueryAsync``2(System.String,System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new { age = 25 })
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="cmdText"></param>
 | 
			
		||||
            <param name="parms"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:FreeSql.IAop.ParseExpression">
 | 
			
		||||
            <summary>
 | 
			
		||||
            可自定义解析表达式
 | 
			
		||||
@@ -2710,159 +2857,3 @@
 | 
			
		||||
        </member>
 | 
			
		||||
    </members>
 | 
			
		||||
</doc>
 | 
			
		||||
 </member>
 | 
			
		||||
        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.Or``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
			
		||||
            <summary>
 | 
			
		||||
            使用 or 拼接两个 lambda 表达式
 | 
			
		||||
            </summary>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.Or``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Boolean,System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
			
		||||
            <summary>
 | 
			
		||||
            使用 or 拼接两个 lambda 表达式
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T"></typeparam>
 | 
			
		||||
            <param name="exp1"></param>
 | 
			
		||||
            <param name="condition">true 时生效</param>
 | 
			
		||||
            <param name="exp2"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.Not``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Boolean)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            将 lambda 表达式取反
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T"></typeparam>
 | 
			
		||||
            <param name="exp"></param>
 | 
			
		||||
            <param name="condition">true 时生效</param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:FreeUtil.NewMongodbId">
 | 
			
		||||
            <summary>
 | 
			
		||||
            生成类似Mongodb的ObjectId有序、不重复Guid
 | 
			
		||||
            </summary>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Insert``1">
 | 
			
		||||
            <summary>
 | 
			
		||||
            插入数据
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Insert``1(``0)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            插入数据,传入实体
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="source"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Insert``1(``0[])">
 | 
			
		||||
            <summary>
 | 
			
		||||
            插入数据,传入实体数组
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="source"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Insert``1(System.Collections.Generic.List{``0})">
 | 
			
		||||
            <summary>
 | 
			
		||||
            插入数据,传入实体集合
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="source"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Insert``1(System.Collections.Generic.IEnumerable{``0})">
 | 
			
		||||
            <summary>
 | 
			
		||||
            插入数据,传入实体集合
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="source"></param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Update``1">
 | 
			
		||||
            <summary>
 | 
			
		||||
            修改数据
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Update``1(System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Select``1">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询数据
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Select``1(System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Delete``1">
 | 
			
		||||
            <summary>
 | 
			
		||||
            删除数据
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Delete``1(System.Object)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
 | 
			
		||||
            </summary>
 | 
			
		||||
            <typeparam name="T1"></typeparam>
 | 
			
		||||
            <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
 | 
			
		||||
            <returns></returns>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Transaction(System.Action)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            开启事务(不支持异步),60秒未执行完将自动提交
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="handler">事务体 () => {}</param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="M:IFreeSql.Transaction(System.Action,System.TimeSpan)">
 | 
			
		||||
            <summary>
 | 
			
		||||
            开启事务(不支持异步)
 | 
			
		||||
            </summary>
 | 
			
		||||
            <param name="handler">事务体 () => {}</param>
 | 
			
		||||
            <param name="timeout">超时,未执行完将自动提交</param>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:IFreeSql.Ado">
 | 
			
		||||
            <summary>
 | 
			
		||||
            数据库访问对象
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:IFreeSql.Aop">
 | 
			
		||||
            <summary>
 | 
			
		||||
            所有拦截方法都在这里
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:IFreeSql.CodeFirst">
 | 
			
		||||
            <summary>
 | 
			
		||||
            CodeFirst 模式开发相关方法
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:IFreeSql.DbFirst">
 | 
			
		||||
            <summary>
 | 
			
		||||
            DbFirst 模式开发相关方法
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
        <member name="P:IFreeSql.GlobalFilter">
 | 
			
		||||
            <summary>
 | 
			
		||||
            全局过滤设置,可默认附加为 Select/Update/Delete 条件
 | 
			
		||||
            </summary>
 | 
			
		||||
        </member>
 | 
			
		||||
    </members>
 | 
			
		||||
</doc>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@ using System.Linq.Expressions;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using FreeSql.DataAnnotations;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
 | 
			
		||||
namespace FreeSql.Internal
 | 
			
		||||
{
 | 
			
		||||
@@ -496,6 +498,8 @@ namespace FreeSql.Internal
 | 
			
		||||
            tsc.mapType = null;
 | 
			
		||||
            return $"{left} {oper} {right}";
 | 
			
		||||
        }
 | 
			
		||||
        static ConcurrentDictionary<Type, bool> _dicTypeExistsExpressionCallAttribute = new ConcurrentDictionary<Type, bool>();
 | 
			
		||||
        static ConcurrentDictionary<Type, FieldInfo[]> _dicTypeExpressionCallClassContextFields = new ConcurrentDictionary<Type, FieldInfo[]>();
 | 
			
		||||
        public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc)
 | 
			
		||||
        {
 | 
			
		||||
            if (exp == null) return "";
 | 
			
		||||
@@ -535,6 +539,38 @@ namespace FreeSql.Internal
 | 
			
		||||
                case ExpressionType.Call:
 | 
			
		||||
                    tsc.mapType = null;
 | 
			
		||||
                    var exp3 = exp as MethodCallExpression;
 | 
			
		||||
                    if (exp3.Object == null && _dicTypeExistsExpressionCallAttribute.GetOrAdd(exp3.Method.DeclaringType, dttp => dttp.GetCustomAttributes(typeof(ExpressionCallAttribute), true).Any()))
 | 
			
		||||
                    {
 | 
			
		||||
                        var ecc = new ExpressionCallContext { DataType = _ado.DataType };
 | 
			
		||||
                        var exp3MethodParams = exp3.Method.GetParameters();
 | 
			
		||||
                        for (var a = 0; a < exp3.Arguments.Count; a++)
 | 
			
		||||
                            if (exp3.Arguments[a].Type != typeof(ExpressionCallContext))
 | 
			
		||||
                                ecc.Values.Add(exp3MethodParams[a].Name, ExpressionLambdaToSql(exp3.Arguments[a], tsc));
 | 
			
		||||
 | 
			
		||||
                        var exp3InvokeParams = new object[exp3.Arguments.Count];
 | 
			
		||||
                        for (var a = 0; a < exp3.Arguments.Count; a++)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (exp3.Arguments[a].Type != typeof(ExpressionCallContext))
 | 
			
		||||
                                exp3InvokeParams[a] = exp3.Arguments[a].Type.CreateInstanceGetDefaultValue();
 | 
			
		||||
                            else
 | 
			
		||||
                                exp3InvokeParams[a] = ecc;
 | 
			
		||||
                        }
 | 
			
		||||
                        var eccFields = _dicTypeExpressionCallClassContextFields.GetOrAdd(exp3.Method.DeclaringType, dttp => 
 | 
			
		||||
                            dttp.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Static).Where(a => a.FieldType == typeof(ThreadLocal<ExpressionCallContext>)).ToArray());
 | 
			
		||||
                        if (eccFields.Any() == false)
 | 
			
		||||
                            throw new Exception($"自定义表达式解析错误:类型 {exp3.Method.DeclaringType} 需要定义 static ThreadLocal<ExpressionCallContext> 字段、字段、字段(重要三次提醒)");
 | 
			
		||||
                        foreach (var eccField in eccFields)
 | 
			
		||||
                            typeof(ThreadLocal<ExpressionCallContext>).GetProperty("Value").SetValue(eccField.GetValue(null), ecc, null);
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            return string.Concat(exp3.Method.Invoke(null, exp3InvokeParams));
 | 
			
		||||
                        }
 | 
			
		||||
                        finally
 | 
			
		||||
                        {
 | 
			
		||||
                            foreach (var eccField in eccFields)
 | 
			
		||||
                                typeof(ThreadLocal<ExpressionCallContext>).GetProperty("Value").SetValue(eccField.GetValue(null), null, null);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    var callType = exp3.Object?.Type ?? exp3.Method.DeclaringType;
 | 
			
		||||
                    string other3Exp = null;
 | 
			
		||||
                    switch (callType.FullName)
 | 
			
		||||
 
 | 
			
		||||
@@ -170,10 +170,7 @@ namespace FreeSql.Internal
 | 
			
		||||
                if (colattr.IsNullable == false && colattr.DbDefautValue == null)
 | 
			
		||||
                {
 | 
			
		||||
                    var citype = colattr.MapType.IsNullableType() ? colattr.MapType.GetGenericArguments().FirstOrDefault() : colattr.MapType;
 | 
			
		||||
                    if (citype.IsArray)
 | 
			
		||||
                        colattr.DbDefautValue = Array.CreateInstance(citype, 0);
 | 
			
		||||
                    else
 | 
			
		||||
                        colattr.DbDefautValue = Activator.CreateInstance(citype);
 | 
			
		||||
                    colattr.DbDefautValue = citype.CreateInstanceGetDefaultValue();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                trytb.Columns.Add(colattr.Name, col);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user