- 增加 FreeSql.Internal.Utils.TypeHandlers 自定义类型映射;

This commit is contained in:
2881099 2023-08-28 18:59:33 +08:00
parent d6823b6a21
commit 0d0e49fea9
7 changed files with 149 additions and 120 deletions

View File

@ -600,6 +600,12 @@ namespace base_entity
BaseEntity.Initialization(fsql, () => _asyncUow.Value);
#endregion
FreeSql.Internal.Utils.TypeHandlers.TryAdd(typeof(TestIdAndIdentity), new String_TestIdAndIdentity());
fsql.Insert(new TypeHandler01 { id = Guid.NewGuid(), json = new TestIdAndIdentity { Id = 101, IdentityId = 10101 } }).ExecuteAffrows();
fsql.Insert(new TypeHandler01 { id = Guid.NewGuid(), json = new TestIdAndIdentity { Id = 102, IdentityId = 10202 } }).ExecuteAffrows();
var th01s = fsql.Select<TypeHandler01>().ToList();
var testr1 = fsql.Ado.ExecuteConnectTest();
var dict = new List<Dictionary<string, object>>();
@ -2578,11 +2584,29 @@ var sql11111 = fsql.Select<Class1111>()
public ProducerConfig PConfig { get; set; }
}
class TestIdAndIdentity
{
class TestIdAndIdentity
{
[Column(IsPrimary = true)]
public int Id { get; set; }
[Column(IsIdentity = true)]
public int IdentityId { get; set; }
}
class TypeHandler01
{
public Guid id { get; set; }
[Column(MapType = typeof(string), StringLength = -1)]
public TestIdAndIdentity json { get; set; }
}
class String_TestIdAndIdentity : TypeHandler<TestIdAndIdentity>
{
public override object Serialize(TestIdAndIdentity value)
{
return JsonConvert.SerializeObject(value);
}
public override TestIdAndIdentity Deserialize(object value)
{
return JsonConvert.DeserializeObject<TestIdAndIdentity>((string)value);
}
}
}

View File

@ -733,6 +733,15 @@
<param name="modelBuilder"></param>
<returns></returns>
</member>
<member name="M:FreeSqlDbContextExtensions.ApplyConfigurationsFromAssembly(FreeSql.ICodeFirst,System.Reflection.Assembly,System.Func{System.Type,System.Boolean})">
<summary>
根据Assembly扫描所有继承IEntityTypeConfiguration&lt;T&gt;的配置类
</summary>
<param name="codeFirst"></param>
<param name="assembly"></param>
<param name="predicate"></param>
<returns></returns>
</member>
<member name="M:FreeSqlDbContextExtensions.CreateDbContext(IFreeSql)">
<summary>
创建普通数据上下文档对象

View File

@ -1084,82 +1084,6 @@
</summary>
<returns></returns>
</member>
<member name="T:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder">
<summary>
动态创建实体类型
</summary>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.#ctor(IFreeSql,System.String,System.Attribute[])">
<summary>
配置Class
</summary>
<param name="className">类名</param>
<param name="attributes">类标记的特性[Table(Name = "xxx")] [Index(xxxx)]</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Boolean,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="isOverride">该属性是否重写父类属性</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Boolean,System.Object,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="isOverride">该属性是否重写父类属性</param>
<param name="defaultValue">属性默认值</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Extend(System.Type)">
<summary>
配置父类
</summary>
<param name="superClass">父类类型</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.OverrideProperty(System.Reflection.Emit.TypeBuilder@,System.Reflection.Emit.MethodBuilder,FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.PropertyMethodEnum,System.String)">
<summary>
Override属性
</summary>
<param name="typeBuilder"></param>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Build">
<summary>
Emit动态创建出Class - Type
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.FirstCharToLower(System.String)">
<summary>
首字母小写
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.FirstCharToUpper(System.String)">
<summary>
首字母大写
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(IFreeSql,System.Type,System.Object,System.Boolean,System.String)">
<summary>
获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null
@ -5824,28 +5748,6 @@
请使用 fsql.InsertDict(dict) 方法插入字典数据
</summary>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.DynamicEntity(FreeSql.ICodeFirst,System.String,System.Attribute[])">
<summary>
动态构建Class Type
</summary>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.CreateInstance(FreeSql.Internal.Model.TableInfo,System.Collections.Generic.Dictionary{System.String,System.Object})">
<summary>
根据字典,创建 table 对应的实体对象
</summary>
<param name="table"></param>
<param name="dict"></param>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.CreateDictionary(FreeSql.Internal.Model.TableInfo,System.Object)">
<summary>
根据实体对象,创建 table 对应的字典
</summary>
<param name="table"></param>
<param name="instance"></param>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.Between(System.DateTime,System.DateTime,System.DateTime)">
<summary>
C# that >= between &amp;&amp; that &lt;= and<para></para>

View File

@ -7,6 +7,10 @@ using System.Reflection;
using FreeSql.DataAnnotations;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using System.Linq.Expressions;
using System.Runtime;
using FreeSql.Internal.Model.Interface;
using System.Threading;
namespace FreeSql
{
@ -445,7 +449,8 @@ namespace FreeSql
}
catch { }
var dyattr = attrs?.Where(a => {
var dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.Name == "MaxLengthAttribute";
}).FirstOrDefault();
if (dyattr != null)
@ -457,7 +462,8 @@ namespace FreeSql
}
}
dyattr = attrs?.Where(a => {
dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.FullName == "System.ComponentModel.DataAnnotations.RequiredAttribute";
}).FirstOrDefault();
if (dyattr != null)
@ -465,7 +471,8 @@ namespace FreeSql
e.ModifyResult.IsNullable = false;
}
dyattr = attrs?.Where(a => {
dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.FullName == "System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute";
}).FirstOrDefault();
if (dyattr != null)
@ -473,7 +480,8 @@ namespace FreeSql
e.ModifyResult.IsIgnore = true;
}
dyattr = attrs?.Where(a => {
dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.FullName == "System.ComponentModel.DataAnnotations.Schema.ColumnAttribute";
}).FirstOrDefault();
if (dyattr != null)
@ -490,7 +498,8 @@ namespace FreeSql
e.ModifyResult.DbType = typeName;
}
dyattr = attrs?.Where(a => {
dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.FullName == "System.ComponentModel.DataAnnotations.KeyAttribute";
}).FirstOrDefault();
if (dyattr != null)
@ -498,7 +507,8 @@ namespace FreeSql
e.ModifyResult.IsPrimary = true;
}
dyattr = attrs?.Where(a => {
dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.FullName == "System.ComponentModel.DataAnnotations.StringLengthAttribute";
}).FirstOrDefault();
if (dyattr != null)
@ -512,12 +522,13 @@ namespace FreeSql
}
//https://github.com/dotnetcore/FreeSql/issues/378
dyattr = attrs?.Where(a => {
dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.FullName == "System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute";
}).FirstOrDefault();
if (dyattr != null)
{
switch(string.Concat(dyattr.GetType().GetProperty("DatabaseGeneratedOption")?.GetValue(dyattr, null)))
switch (string.Concat(dyattr.GetType().GetProperty("DatabaseGeneratedOption")?.GetValue(dyattr, null)))
{
case "Identity":
case "1":
@ -540,7 +551,8 @@ namespace FreeSql
}
catch { }
var dyattr = attrs?.Where(a => {
var dyattr = attrs?.Where(a =>
{
return ((a as Attribute)?.TypeId as Type)?.FullName == "System.ComponentModel.DataAnnotations.Schema.TableAttribute";
}).FirstOrDefault();
if (dyattr != null)
@ -565,7 +577,59 @@ namespace FreeSql
(ret.Select<object>() as Select0Provider)._commonUtils.IsQuoteSqlName = _isQuoteSqlName;
}
if (Interlocked.CompareExchange(ref _isTypeHandlered, 1, 0) == 0)
{
FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type2) =>
{
if (FreeSql.Internal.Utils.TypeHandlers.TryGetValue(type2, out var typeHandler)) return Expression.IfThenElse(
Expression.TypeIs(valueExp, type2),
Expression.Return(returnTarget, valueExp),
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(
Expression.Constant(typeHandler, typeof(ITypeHandler)),
typeof(ITypeHandler).GetMethod(nameof(typeHandler.Deserialize)),
Expression.Convert(valueExp, typeof(object))), type2))
);
return null;
});
}
ret.Aop.ConfigEntityProperty += (s, e) =>
{
foreach (var typeHandler in FreeSql.Internal.Utils.TypeHandlers.Values)
{
if (e.Property.PropertyType == typeHandler.Type)
{
if (_dicTypeHandlerTypes.ContainsKey(e.Property.PropertyType) == false &&
FreeSql.Internal.Utils.dicExecuteArrayRowReadClassOrTuple.ContainsKey(e.Property.PropertyType))
return; //基础类型无效
if (_dicTypeHandlerTypes.TryAdd(e.Property.PropertyType, true))
{
lock (_concurrentObj)
{
FreeSql.Internal.Utils.dicExecuteArrayRowReadClassOrTuple[e.Property.PropertyType] = true;
FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionObjectToStringIfThenElse.Add((LabelTarget returnTarget, Expression valueExp, Expression elseExp, Type type2) =>
{
return Expression.IfThenElse(
Expression.TypeIs(valueExp, e.Property.PropertyType),
Expression.Return(returnTarget, Expression.Call(
Expression.Constant(typeHandler, typeof(ITypeHandler)),
typeof(ITypeHandler).GetMethod(nameof(typeHandler.Serialize)),
Expression.Convert(valueExp, typeof(object))
), typeof(object)),
elseExp);
});
}
}
break;
}
}
};
return ret;
}
static int _isTypeHandlered = 0;
ConcurrentDictionary<Type, bool> _dicTypeHandlerTypes = new ConcurrentDictionary<Type, bool>();
object _concurrentObj = new object();
}
}

View File

@ -78,5 +78,4 @@ namespace FreeSql.Internal
/// </summary>
ToLower
}
}

View File

@ -0,0 +1,26 @@
using FreeSql.Internal.Model.Interface;
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSql.Internal.Model
{
namespace Interface
{
public interface ITypeHandler
{
Type Type { get; }
object Deserialize(object value);
object Serialize(object value);
}
}
public abstract class TypeHandler<T> : ITypeHandler
{
public abstract T Deserialize(object value);
public abstract object Serialize(T value);
public Type Type => typeof(T);
object ITypeHandler.Deserialize(object value) => this.Deserialize(value);
object ITypeHandler.Serialize(object value) => this.Serialize((T)value);
}
}

View File

@ -1,5 +1,6 @@
using FreeSql.DataAnnotations;
using FreeSql.Internal.Model;
using FreeSql.Internal.Model.Interface;
using System;
using System.Collections;
using System.Collections.Concurrent;
@ -2170,6 +2171,8 @@ namespace FreeSql.Internal
static MethodInfo MethodGuidToBytes = typeof(Utils).GetMethod("GuidToBytes", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(Guid) }, null);
static MethodInfo MethodBytesToGuid = typeof(Utils).GetMethod("BytesToGuid", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(byte[]) }, null);
public static ConcurrentDictionary<Type, ITypeHandler> TypeHandlers { get; } = new ConcurrentDictionary<Type, ITypeHandler>();
public static ConcurrentBag<Func<LabelTarget, Expression, Type, Expression>> GetDataReaderValueBlockExpressionSwitchTypeFullName = new ConcurrentBag<Func<LabelTarget, Expression, Type, Expression>>();
public static ConcurrentBag<Func<LabelTarget, Expression, Expression, Type, Expression>> GetDataReaderValueBlockExpressionObjectToStringIfThenElse = new ConcurrentBag<Func<LabelTarget, Expression, Expression, Type, Expression>>();
public static ConcurrentBag<Func<LabelTarget, Expression, Expression, Type, Expression>> GetDataReaderValueBlockExpressionObjectToBytesIfThenElse = new ConcurrentBag<Func<LabelTarget, Expression, Expression, Type, Expression>>();
@ -2562,7 +2565,9 @@ namespace FreeSql.Internal
{
//if (value == null || value == DBNull.Value) return Activator.CreateInstance(type);
if (type == null) return value;
var func = _dicGetDataReaderValue.GetOrAdd(type, k1 => new ConcurrentDictionary<Type, Func<object, object>>()).GetOrAdd(value?.GetType() ?? type, valueType =>
var valueType = value?.GetType() ?? type;
if (TypeHandlers.TryGetValue(valueType, out var typeHandler)) return typeHandler.Serialize(value);
var func = _dicGetDataReaderValue.GetOrAdd(type, k1 => new ConcurrentDictionary<Type, Func<object, object>>()).GetOrAdd(valueType, valueType2 =>
{
var parmExp = Expression.Parameter(typeof(object), "value");
var exp = GetDataReaderValueBlockExpression(type, parmExp);