mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 18:52:50 +08:00
- 增加 FreeSql.Internal.Utils.TypeHandlers 自定义类型映射;
This commit is contained in:
parent
d6823b6a21
commit
0d0e49fea9
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<T>的配置类
|
||||
</summary>
|
||||
<param name="codeFirst"></param>
|
||||
<param name="assembly"></param>
|
||||
<param name="predicate"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:FreeSqlDbContextExtensions.CreateDbContext(IFreeSql)">
|
||||
<summary>
|
||||
创建普通数据上下文档对象
|
||||
|
@ -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 && that <= and<para></para>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -78,5 +78,4 @@ namespace FreeSql.Internal
|
||||
/// </summary>
|
||||
ToLower
|
||||
}
|
||||
|
||||
}
|
26
FreeSql/Internal/Model/TypeHandler.cs
Normal file
26
FreeSql/Internal/Model/TypeHandler.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user