public static string TypeToDbTypeStatement(EntityPropertyDef propertyDef, EngineType engineType) { //查看属性自定义 if (propertyDef.TypeConverter != null) { return(propertyDef.TypeConverter.Statement); } Type trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type; //查看全局TypeConvert ConverterInfo?converterInfo = GetGlobalConverterInfo(trueType, engineType); if (converterInfo != null) { return(converterInfo.Statement); } //默认处理 if (trueType.IsEnum) { return(GetGlobalConverterInfo(typeof(string), engineType) !.Statement); } throw Exceptions.EntityHasNotSupportedPropertyType(type: propertyDef.EntityDef.EntityFullName, propertyTypeName: (propertyDef.NullableUnderlyingType ?? propertyDef.Type).FullName, propertyName: propertyDef.Name); }
public static object TypeValueToDbValue(object?typeValue, EntityPropertyDef propertyDef, EngineType engineType) { if (typeValue == null) { return(DBNull.Value); } //查看当前Property的TypeConvert if (propertyDef.TypeConverter != null) { return(propertyDef.TypeConverter.TypeValueToDbValue(typeValue, propertyDef.Type)); } Type trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type; //查看全局TypeConvert ITypeConverter?globalConverter = GetGlobalTypeConverter(trueType, engineType); if (globalConverter != null) { return(globalConverter.TypeValueToDbValue(typeValue, trueType)); } //默认 if (trueType.IsEnum) { return(typeValue.ToString() !); } return(typeValue); }
public static string TypeValueToDbValueStatement(object?typeValue, bool quotedIfNeed, EngineType engineType) { if (typeValue == null) { return("null"); } Type type = typeValue.GetType(); EntityPropertyDef propertyDef = new EntityPropertyDef { Type = type, NullableUnderlyingType = Nullable.GetUnderlyingType(type), TypeConverter = null }; object dbValue = TypeValueToDbValue(typeValue, propertyDef, engineType); string statement = dbValue switch { //null => "null", //Enum e => e.ToString(), DBNull _ => "null", DateTime _ => throw Exceptions.UseDateTimeOffsetOnly(), DateTimeOffset dt => dt.ToString(@"yyyy\-MM\-dd HH\:mm\:ss.FFFFFFFzzz", GlobalSettings.Culture), bool b => b ? "1" : "0", _ => dbValue.ToString() ! }; if (!quotedIfNeed || statement == "null" || !SqlHelper.IsValueNeedQuoted(dbValue !.GetType())) { return(statement); } return(SqlHelper.GetQuoted(statement)); }
public static string CreateDeleteSql(EntityDef entityDef) { EntityPropertyDef deletedProperty = entityDef.GetPropertyDef(nameof(Entity.Deleted)) !; EntityPropertyDef versionProperty = entityDef.GetPropertyDef(nameof(Entity.Version)) !; return($"update {entityDef.DbTableReservedName} set {versionProperty.DbReservedName}={versionProperty.DbReservedName}+1, {deletedProperty.DbReservedName}=1"); }
public static string CreateUpdateEntitySql(EntityDef entityDef, int number = 0) { StringBuilder args = new StringBuilder(); foreach (EntityPropertyDef propertyInfo in entityDef.PropertyDefs) { if (propertyInfo.IsPrimaryKey) { continue; } args.Append($" {propertyInfo.DbReservedName}={propertyInfo.DbParameterizedName}_{number},"); } args.RemoveLast(); EntityPropertyDef primaryKeyProperty = entityDef.PrimaryKeyPropertyDef; EntityPropertyDef deletedProperty = entityDef.GetPropertyDef(nameof(Entity.Deleted)) !; EntityPropertyDef versionProperty = entityDef.GetPropertyDef(nameof(Entity.Version)) !; StringBuilder where = new StringBuilder(); where.Append($"{primaryKeyProperty.DbReservedName}={primaryKeyProperty.DbParameterizedName}_{number} AND "); where.Append($"{versionProperty.DbReservedName}={versionProperty.DbParameterizedName}_{number} - 1 AND "); where.Append($"{deletedProperty.DbReservedName}=0"); return($"UPDATE {entityDef.DbTableReservedName} SET {args} WHERE {where};"); }
public static object?DbValueToTypeValue(object dbValue, EntityPropertyDef propertyDef, EngineType engineType) //Type targetType) { Type dbValueType = dbValue.GetType(); if (dbValueType == typeof(DBNull)) { return(null); } //查看属性TypeConverter if (propertyDef.TypeConverter != null) { return(propertyDef.TypeConverter.DbValueToTypeValue(dbValue, propertyDef.Type)); } Type trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type; object?typeValue; //查看全局TypeConverter ITypeConverter?globalConverter = GetGlobalTypeConverter(trueType, engineType); if (globalConverter != null) { typeValue = globalConverter.DbValueToTypeValue(dbValue, trueType); } else { //默认 if (trueType.IsEnum) { typeValue = Enum.Parse(trueType, dbValue.ToString() !, true); } else if (trueType != dbValueType) { typeValue = Convert.ChangeType(dbValue, trueType, GlobalSettings.Culture); } else { typeValue = dbValue; } } //处理Nullable if (propertyDef.NullableUnderlyingType == null) { return(typeValue); } ConstructorInfo?ctor = propertyDef.Type.GetConstructor(new Type[] { propertyDef.NullableUnderlyingType }); return(ctor !.Invoke(new object?[] { typeValue })); }
public async Task Test_EntityMapperPerformanceAsync(int index) { index++; IDatabase database = _sqlite; IList <BookEntity_Client>?books = Mocker.GetBooks_Client(500); TransactionContext?trans = await _sqlIteTransaction.BeginTransactionAsync <BookEntity_Client>().ConfigureAwait(false); IEnumerable <BookEntity_Client> re = await database.RetrieveAsync <BookEntity_Client>(b => b.Deleted, trans).ConfigureAwait(false); await database.AddAsync <BookEntity_Client>(Mocker.GetBooks_Client(1)[0], "", trans).ConfigureAwait(false); try { //await database.AddAsync<BookEntity>(books[0], "", trans); await database.BatchAddAsync(books, "x", trans).ConfigureAwait(false); await _sqlIteTransaction.CommitAsync(trans).ConfigureAwait(false); } catch { await _sqlIteTransaction.RollbackAsync(trans).ConfigureAwait(false); } Stopwatch stopwatch = new Stopwatch(); using SqliteConnection mySqlConnection = new SqliteConnection("Data Source=sqlite_test2.db"); //time = 0; int loop = 10; TimeSpan time0 = TimeSpan.Zero, time1 = TimeSpan.Zero, time2 = TimeSpan.Zero, time3 = TimeSpan.Zero; for (int cur = 0; cur < loop; ++cur) { await mySqlConnection.OpenAsync().ConfigureAwait(false); using SqliteCommand command0 = new SqliteCommand("select * from tb_bookentity_client limit 1000", mySqlConnection); SqliteDataReader?reader0 = await command0.ExecuteReaderAsync().ConfigureAwait(false); List <BookEntity_Client> list1 = new List <BookEntity_Client>(); List <BookEntity_Client> list2 = new List <BookEntity_Client>(); List <BookEntity_Client> list3 = new List <BookEntity_Client>(); int len = reader0.FieldCount; EntityPropertyDef[] propertyDefs = new EntityPropertyDef[len]; MethodInfo[] setMethods = new MethodInfo[len]; EntityDef definition = EntityDefFactory.GetDef <BookEntity_Client>() !; for (int i = 0; i < len; ++i) { propertyDefs[i] = definition.GetPropertyDef(reader0.GetName(i)) !; setMethods[i] = propertyDefs[i].SetMethod; } Func <IDataReader, object> mapper1 = EntityMapperDelegateCreator.CreateToEntityDelegate(definition, reader0, 0, definition.FieldCount, false, Database.Engine.EngineType.SQLite); //Warning: 如果用Dapper,小心DateTimeOffset的存储,会丢失offset,然后转回来时候,会加上当地时间的offset TypeHandlerHelper.AddTypeHandlerImpl(typeof(DateTimeOffset), new DateTimeOffsetTypeHandler(), false); Func <IDataReader, object> mapper2 = DataReaderTypeMapper.GetTypeDeserializerImpl(typeof(BookEntity_Client), reader0); Stopwatch stopwatch1 = new Stopwatch(); Stopwatch stopwatch2 = new Stopwatch(); Stopwatch stopwatch3 = new Stopwatch(); while (reader0.Read()) { stopwatch1.Start(); object obj1 = mapper1(reader0); list1.Add((BookEntity_Client)obj1); stopwatch1.Stop(); stopwatch2.Start(); object obj2 = mapper2(reader0); list2.Add((BookEntity_Client)obj2); stopwatch2.Stop(); stopwatch3.Start(); BookEntity_Client item = new BookEntity_Client(); for (int i = 0; i < len; ++i) { EntityPropertyDef property = propertyDefs[i]; object?value = TypeConvert.DbValueToTypeValue(reader0[i], property, Database.Engine.EngineType.SQLite); if (value != null) { setMethods[i].Invoke(item, new object?[] { value }); } } list3.Add(item); stopwatch3.Stop(); } time1 += stopwatch1.Elapsed; time2 += stopwatch2.Elapsed; time3 += stopwatch3.Elapsed; await reader0.DisposeAsync().ConfigureAwait(false); command0.Dispose(); await mySqlConnection.CloseAsync().ConfigureAwait(false); } _output.WriteLine("Emit Coding : " + (time1.TotalMilliseconds / (loop * 1.0)).ToString(CultureInfo.InvariantCulture)); _output.WriteLine("Dapper : " + (time2.TotalMilliseconds / (loop * 1.0)).ToString(CultureInfo.InvariantCulture)); _output.WriteLine("Reflection : " + (time3.TotalMilliseconds / (loop * 1.0)).ToString(CultureInfo.InvariantCulture)); }
public static string CreateAddOrUpdateSql(EntityDef entityDef, EngineType engineType, bool returnId, int number = 0) { StringBuilder addArgs = new StringBuilder(); StringBuilder selectArgs = new StringBuilder(); StringBuilder addValues = new StringBuilder(); StringBuilder updatePairs = new StringBuilder(); foreach (EntityPropertyDef propertyDef in entityDef.PropertyDefs) { if (returnId) { selectArgs.Append($"{propertyDef.DbReservedName},"); } if (propertyDef.IsAutoIncrementPrimaryKey) { continue; } addArgs.Append($"{propertyDef.DbReservedName},"); addValues.Append($"{propertyDef.DbParameterizedName}_{number},"); if (propertyDef.IsPrimaryKey) { continue; } if (propertyDef.Name == nameof(Entity.Version) || propertyDef.Name == nameof(Entity.CreateTime)) { continue; } updatePairs.Append($" {propertyDef.DbReservedName}={propertyDef.DbParameterizedName}_{number},"); } EntityPropertyDef versionProperty = entityDef.GetPropertyDef(nameof(Entity.Version)) !; updatePairs.Append($"{versionProperty.DbReservedName}={versionProperty.DbReservedName} + 1"); if (returnId) { selectArgs.RemoveLast(); } addValues.RemoveLast(); addArgs.RemoveLast(); EntityPropertyDef primaryKeyProperty = entityDef.PrimaryKeyPropertyDef; string sql = $"insert into {entityDef.DbTableReservedName}({addArgs}) values({addValues}) {OnDuplicateKeyUpdateStatement(engineType, primaryKeyProperty)} {updatePairs};"; if (returnId) { if (entityDef.IsIdAutoIncrement) { sql += $"select {selectArgs} from {entityDef.DbTableReservedName} where {primaryKeyProperty.DbReservedName} = {GetLastInsertIdStatement(engineType)};"; } else { sql += $"select {selectArgs} from {entityDef.DbTableReservedName} where {primaryKeyProperty.DbReservedName} = {primaryKeyProperty.DbParameterizedName}_{number};"; } } return(sql); }
/// <summary> /// EmitEntityMapper /// </summary> /// <param name="def"></param> /// <param name="reader"></param> /// <param name="startIndex"></param> /// <param name="length"></param> /// <param name="returnNullIfFirstNull"></param> /// <param name="engineType"></param> /// <param name="il"></param> /// <exception cref="DatabaseException"></exception> private static void EmitEntityMapper(EntityDef def, IDataReader reader, int startIndex, int length, bool returnNullIfFirstNull, EngineType engineType, ILGenerator il) { try { List <EntityPropertyDef> propertyDefs = new List <EntityPropertyDef>(); for (int i = startIndex; i < startIndex + length; ++i) { propertyDefs.Add(def.GetPropertyDef(reader.GetName(i)) ?? throw Exceptions.EntityError(def.EntityFullName, reader.GetName(i), "Lack PropertyDef")); } LocalBuilder returnValueLocal = il.DeclareLocal(def.EntityType); LocalBuilder enumStringTempLocal = il.DeclareLocal(typeof(string)); LocalBuilder timespanZeroLocal = il.DeclareLocal(typeof(TimeSpan)); LocalBuilder entityTypeLocal = il.DeclareLocal(typeof(Type)); System.Reflection.Emit.Label allFinished = il.DefineLabel(); ConstructorInfo ctor = def.EntityType.GetDefaultConstructor() ?? throw Exceptions.EntityError(def.EntityFullName, "", "实体没有默认构造函数"); il.Emit(OpCodes.Ldtoken, def.EntityType); il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null); il.Emit(OpCodes.Stloc, entityTypeLocal); il.Emit(OpCodes.Newobj, ctor); //emitter.NewObject(ctor); il.Emit(OpCodes.Stloc, returnValueLocal); //emitter.StoreLocal(returnValueLocal); il.Emit(OpCodes.Ldloc, returnValueLocal); //emitter.LoadLocal(returnValueLocal); // [target] bool firstProperty = true; for (int index = 0; index < propertyDefs.Count; ++index) { bool hasConverter = false; System.Reflection.Emit.Label dbNullLabel = il.DefineLabel(); System.Reflection.Emit.Label finishLable = il.DefineLabel(); Type dbValueType = reader.GetFieldType(index + startIndex); il.Emit(OpCodes.Dup); //emitter.Duplicate(); // stack is now [target][target] EntityPropertyDef propertyDef = propertyDefs[index]; Type trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type; //======属性自定义Converter if (propertyDef.TypeConverter != null) { //il.Emit(OpCodes.Ldtoken, def.EntityType); //il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null); il.Emit(OpCodes.Ldloc, entityTypeLocal); il.Emit(OpCodes.Ldstr, propertyDef.Name); //emitter.LoadConstant(propertyDef.PropertyInfo.Name); // stack is now [target][target][EntityType][PropertyName] il.EmitCall(OpCodes.Call, _getPropertyTypeConverterMethod, null); //emitter.Call(typeof(DatabaseEntityDef).GetMethod(nameof(DatabaseEntityDef.OnlyForEmitGetPropertyTypeConverter))); // stack is now [target][target][TypeConverter] hasConverter = true; } else { //======全局Converter ITypeConverter?globalTypeConverter = TypeConvert.GetGlobalTypeConverter(trueType, engineType); if (globalTypeConverter != null) { il.Emit(OpCodes.Ldtoken, trueType); il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null); EmitInt32(il, (int)engineType); il.EmitCall(OpCodes.Call, _getGlobalTypeConverterMethod, null); //stack is now [target][target][TypeConverter] hasConverter = true; } } //===获取数据库值========================================================================= il.Emit(OpCodes.Ldarg_0); //emitter.LoadArgument(0);// stack is now [...][reader] EmitInt32(il, index + startIndex); //emitter.LoadConstant(index); // stack is now [...][reader][index] il.EmitCall(OpCodes.Callvirt, _dataReaderGetItemMethod, null); //emitter.CallVirtual(ReflectionHelper.GetItem);// stack is now [...][value-as-object] //处理Null il.Emit(OpCodes.Dup); //emitter.Duplicate(); //stack is now [...][value-as-object][value-as-object] il.Emit(OpCodes.Isinst, typeof(DBNull)); //emitter.IsInstance(typeof(DBNull));//stack is now [...][value-as-object][DbNull/null] il.Emit(OpCodes.Brtrue_S, dbNullLabel); //emitter.BranchIfTrue(dbNullLabel);//stack is now [...][value-as-object] #region DbValueToTypeValue,逻辑同DatabaseConverty.DbValueToTypeValue一致 if (propertyDef.TypeConverter != null) { // stack is now [target][target][TypeConverter][value-as-object] il.Emit(OpCodes.Ldtoken, propertyDef.Type); il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null); //stack is now [target][target][TypeConverter][value-as-object][propertyType] il.EmitCall(OpCodes.Callvirt, _getTypeConverterDbValueToTypeValueMethod, null); //emitter.CallVirtual(typeof(DatabaseTypeConverter).GetMethod(nameof(DatabaseTypeConverter.DbValueToTypeValue))); il.Emit(OpCodes.Unbox_Any, propertyDef.Type); //emitter.UnboxAny(propertyDef.Type); // stack is now [target][target][TypeValue] } else { if (hasConverter) { //全局Converter // stack is now [target][target][TypeConverter][value-as-object] il.Emit(OpCodes.Ldtoken, trueType); il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null); //stack is now [target][target][TypeConverter][value-as-object][trueType] il.EmitCall(OpCodes.Callvirt, _getTypeConverterDbValueToTypeValueMethod, null); //emitter.CallVirtual(typeof(DatabaseTypeConverter).GetMethod(nameof(DatabaseTypeConverter.DbValueToTypeValue))); il.Emit(OpCodes.Unbox_Any, trueType); //emitter.UnboxAny(propertyDef.Type); // stack is now [target][target][TypeValue] } else { //默认 // stack is now [target][target][value-as-object] if (trueType.IsEnum) { // stack is now [target][target][value-as-object] il.Emit(OpCodes.Castclass, typeof(string)); //emitter.CastClass<string>(); //stack is now [target][target][string] il.Emit(OpCodes.Stloc, enumStringTempLocal); //emitter.StoreLocal(enumStringTempLocal); //stack is now [target][target] if (propertyDef.NullableUnderlyingType != null) { il.Emit(OpCodes.Ldtoken, propertyDef.NullableUnderlyingType); //emitter.LoadConstant(propertyDef.NullableUnderlyingType); } else { il.Emit(OpCodes.Ldtoken, propertyDef.Type); //emitter.LoadConstant(propertyDef.Type);//stack is now[target][target][propertyType-token] } il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null); //emitter.Call(typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)));//stack is now[target][target][propertyType] il.Emit(OpCodes.Ldloc, enumStringTempLocal); //emitter.LoadLocal(enumStringTempLocal);//stack is now[target][target][propertyType][string] il.Emit(OpCodes.Ldc_I4_1); //emitter.LoadConstant(true);//stack is now[target][target][propertyType][string][true] il.EmitCall(OpCodes.Call, _enumParseMethod, null); //emitter.Call(EnumParse);//stack is now[target][target][value] if (propertyDef.NullableUnderlyingType != null) { il.Emit(OpCodes.Unbox_Any, propertyDef.NullableUnderlyingType); //emitter.UnboxAny(propertyDef.NullableUnderlyingType); } else { il.Emit(OpCodes.Unbox_Any, propertyDef.Type); //emitter.UnboxAny(propertyDef.Type); } //stack is now[target][target][typed-value] } else { // stack is now [target][target][value-as-object] if (dbValueType == trueType) { il.Emit(OpCodes.Unbox_Any, trueType); } else { FlexibleConvertBoxedFromHeadOfStack(il, dbValueType, trueType); } //stack is now[target][target][typed-value] } } if (propertyDef.NullableUnderlyingType != null) { il.Emit(OpCodes.Newobj, propertyDef.Type.GetConstructor(new Type[] { propertyDef.NullableUnderlyingType }) !); //emitter.NewObject(propertyDef.Type.GetConstructor(new Type[] { propertyDef.NullableUnderlyingType })); } } #endregion //===赋值================================================================================ // stack is now [target][target][TypeValue] if (propertyDef.Type.IsValueType) { il.EmitCall(OpCodes.Call, propertyDef.SetMethod, null); //emitter.Call(GetPropertySetter(propertyDef.PropertyInfo, def.EntityType)); } else { il.EmitCall(OpCodes.Callvirt, propertyDef.SetMethod, null); //emitter.CallVirtual(GetPropertySetter(propertyDef.PropertyInfo, def.EntityType)); } //stack is now[target] il.Emit(OpCodes.Br_S, finishLable); //emitter.Branch(finishLable); il.MarkLabel(dbNullLabel); //emitter.MarkLabel(dbNullLabel); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Pop); //emitter.Pop(); //emitter.Pop(); if (hasConverter) { il.Emit(OpCodes.Pop); } if (firstProperty && returnNullIfFirstNull) { il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldnull); //stack is now [null] il.Emit(OpCodes.Br, allFinished); } il.MarkLabel(finishLable); //emitter.MarkLabel(finishLable); firstProperty = false; } il.MarkLabel(allFinished); //emitter.StoreLocal(returnValueLocal); //emitter.LoadLocal(returnValueLocal); il.Emit(OpCodes.Ret); //emitter.Return(); } catch (Exception ex) { //string info = ex.GetDebugInfo(); throw Exceptions.MapperError(innerException: ex); } }