Skip to content

Commit ab35671

Browse files
committed
Merge branch 'master' of https://github.com/mikependon/RepoDB into repodb-optimized-batch-statements
2 parents 0819860 + bb49ae3 commit ab35671

File tree

12 files changed

+214
-137
lines changed

12 files changed

+214
-137
lines changed

RepoDb.Benchmarks/RepoDb.Benchmarks.PostgreSql/RepoDb.Benchmarks.PostgreSql.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<PackageReference Include="linq2db.PostgreSQL" Version="4.3.0" />
1414
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
1515
<PackageReference Include="NHibernate" Version="5.4.0" />
16-
<PackageReference Include="Npgsql" Version="7.0.0" />
16+
<PackageReference Include="Npgsql" Version="7.0.4" />
1717
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
1818
</ItemGroup>
1919

RepoDb.Core/RepoDb/Cachers/DbFieldCache.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using RepoDb.Exceptions;
1+
using System;
2+
using RepoDb.Exceptions;
23
using System.Collections.Concurrent;
34
using System.Data;
45
using System.Threading;
@@ -88,13 +89,13 @@ internal static DbFieldCollection GetInternal<TDbConnection>(TDbConnection conne
8889
// Note: For SqlConnection, the ConnectionString is changing if the (Integrated Security=False). Actually for this isolation, the database name is enough.
8990
if (!string.IsNullOrWhiteSpace(connection.Database))
9091
{
91-
key += connection.Database.GetHashCode();
92+
key = HashCode.Combine(key, connection.Database.GetHashCode());
9293
}
9394

9495
// Add the hashcode of the table name
9596
if (string.IsNullOrWhiteSpace(tableName) == false)
9697
{
97-
key += tableName.GetHashCode();
98+
key = HashCode.Combine(key, tableName.GetHashCode());
9899
}
99100

100101
// Try get the value
@@ -177,13 +178,13 @@ internal static async Task<DbFieldCollection> GetAsyncInternal<TDbConnection>(TD
177178
// Note: For SqlConnection, the ConnectionString is changing if the (Integrated Security=False). Actually for this isolation, the database name is enough.
178179
if (!string.IsNullOrWhiteSpace(connection.Database))
179180
{
180-
key += connection.Database.GetHashCode();
181+
key = HashCode.Combine(key, connection.Database.GetHashCode());
181182
}
182183

183184
// Add the hashcode of the table name
184185
if (string.IsNullOrWhiteSpace(tableName) == false)
185186
{
186-
key += tableName.GetHashCode();
187+
key = HashCode.Combine(key, tableName.GetHashCode());
187188
}
188189

189190
// Try get the value

RepoDb.Core/RepoDb/ClassProperty.cs

Lines changed: 22 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ public ClassProperty(Type parentType,
3333
{
3434
declaringType = parentType;
3535
PropertyInfo = property;
36+
37+
typeMapAttribute = new Lazy<TypeMapAttribute>(() => PropertyInfo.GetCustomAttribute<TypeMapAttribute>(), true);
38+
propertyHandlerAttribute = new Lazy<PropertyHandlerAttribute>(() => PropertyInfo.GetCustomAttribute<PropertyHandlerAttribute>(), true);
39+
dbType = new Lazy<DbType?>(() => PropertyInfo.GetDbType(), true);
40+
propertyValueAttributes = new Lazy<IEnumerable<PropertyValueAttribute>>(() => PropertyInfo.GetPropertyValueAttributes(GetDeclaringType()), true);
41+
propertyValueAttribute = new Lazy<PropertyValueAttribute>(() =>
42+
{
43+
return (PropertyInfo.GetCustomAttribute<DbTypeAttribute>() ?? PropertyInfo.GetCustomAttribute<TypeMapAttribute>()) ??
44+
(GetPropertyValueAttributes()
45+
.LastOrDefault(e => string.Equals(nameof(IDbDataParameter.ParameterName), e.PropertyName, StringComparison.OrdinalIgnoreCase)));
46+
}, true);
3647
}
3748

3849
#region Properties
@@ -136,66 +147,43 @@ public IdentityAttribute GetIdentityAttribute()
136147
/*
137148
* GetTypeMapAttribute
138149
*/
139-
private bool isTypeMapAttributeWasSet;
140-
private TypeMapAttribute typeMapAttribute;
150+
private readonly Lazy<TypeMapAttribute> typeMapAttribute;
141151

142152
/// <summary>
143153
/// Gets the <see cref="TypeMapAttribute"/> if present.
144154
/// </summary>
145155
/// <returns>The instance of <see cref="TypeMapAttribute"/>.</returns>
146156
public TypeMapAttribute GetTypeMapAttribute()
147157
{
148-
if (isTypeMapAttributeWasSet)
149-
{
150-
return typeMapAttribute;
151-
}
152-
isTypeMapAttributeWasSet = true;
153-
return typeMapAttribute = PropertyInfo.GetCustomAttribute<TypeMapAttribute>();
158+
return typeMapAttribute.Value;
154159
}
155160

156161
/*
157162
* GetDbTypeAttribute
158163
*/
159-
private bool isDbTypeAttributeWasSet;
160-
private PropertyValueAttribute propertyValueAttribute;
164+
private readonly Lazy<PropertyValueAttribute> propertyValueAttribute;
161165

162166
/// <summary>
163167
/// Gets the <see cref="PropertyValueAttribute"/> if present.
164168
/// </summary>
165169
/// <returns>The instance of <see cref="PropertyValueAttribute"/>.</returns>
166170
public PropertyValueAttribute GetDbTypeAttribute()
167171
{
168-
if (isDbTypeAttributeWasSet)
169-
{
170-
return propertyValueAttribute;
171-
}
172-
isDbTypeAttributeWasSet = true;
173-
return propertyValueAttribute = (PropertyInfo.GetCustomAttribute<DbTypeAttribute>() ??
174-
PropertyInfo.GetCustomAttribute<TypeMapAttribute>()) ??
175-
(GetPropertyValueAttributes()
176-
.Where(
177-
e => string.Equals(nameof(IDbDataParameter.ParameterName), e.PropertyName, StringComparison.OrdinalIgnoreCase))
178-
.LastOrDefault());
172+
return propertyValueAttribute.Value;
179173
}
180174

181175
/*
182176
* GetPropertyHandlerAttribute
183177
*/
184-
private bool isPropertyHandlerAttributeWasSet;
185-
private PropertyHandlerAttribute propertyHandlerAttribute;
178+
private readonly Lazy<PropertyHandlerAttribute> propertyHandlerAttribute;
186179

187180
/// <summary>
188181
/// Gets the <see cref="PropertyHandlerAttribute"/> if present.
189182
/// </summary>
190183
/// <returns>The instance of <see cref="PropertyHandlerAttribute"/>.</returns>
191184
public PropertyHandlerAttribute GetPropertyHandlerAttribute()
192185
{
193-
if (isPropertyHandlerAttributeWasSet)
194-
{
195-
return propertyHandlerAttribute;
196-
}
197-
isPropertyHandlerAttributeWasSet = true;
198-
return propertyHandlerAttribute = PropertyInfo.GetCustomAttribute<PropertyHandlerAttribute>();
186+
return propertyHandlerAttribute.Value;
199187
}
200188

201189
/*
@@ -238,28 +226,20 @@ public PropertyHandlerAttribute GetPropertyHandlerAttribute()
238226
/*
239227
* GetDbType
240228
*/
241-
private bool isDbTypeWasSet;
242-
private DbType? dbType;
229+
private readonly Lazy<DbType?> dbType;
243230

244231
/// <summary>
245232
/// Gets the mapped <see cref="DbType"/> for the current property.
246233
/// </summary>
247234
/// <returns>The mapped <see cref="DbType"/> value.</returns>
248235
public DbType? GetDbType()
249236
{
250-
if (isDbTypeWasSet == true)
251-
{
252-
return dbType;
253-
}
254-
isDbTypeWasSet = true;
255-
return dbType = PropertyInfo.GetDbType();
237+
return dbType.Value;
256238
}
257239

258240
/*
259241
* GetPropertyHandler
260242
*/
261-
private bool propertyHandlerWasSet;
262-
private object propertyHandler;
263243

264244
/// <summary>
265245
/// Gets the mapped property handler object for the current property.
@@ -275,13 +255,7 @@ public object GetPropertyHandler() =>
275255
/// <returns>The mapped property handler object.</returns>
276256
public TPropertyHandler GetPropertyHandler<TPropertyHandler>()
277257
{
278-
if (propertyHandlerWasSet == true)
279-
{
280-
return Converter.ToType<TPropertyHandler>(propertyHandler);
281-
}
282-
propertyHandlerWasSet = true;
283-
propertyHandler = PropertyHandlerCache.Get<TPropertyHandler>(GetDeclaringType(), PropertyInfo);
284-
return Converter.ToType<TPropertyHandler>(propertyHandler);
258+
return Converter.ToType<TPropertyHandler>(PropertyHandlerCache.Get<TPropertyHandler>(GetDeclaringType(), PropertyInfo));
285259
}
286260

287261
/*
@@ -300,21 +274,15 @@ public string GetMappedName() =>
300274
/*
301275
* PropertyHandlerAttributes
302276
*/
303-
private bool isPropertyValueAttributesWasSet;
304-
private IEnumerable<PropertyValueAttribute> propertyValueAttributes;
277+
private readonly Lazy<IEnumerable<PropertyValueAttribute>> propertyValueAttributes;
305278

306279
/// <summary>
307280
/// Gets the list of mapped <see cref="PropertyValueAttribute"/> object for the current property.
308281
/// </summary>
309282
/// <returns>The list of mapped <see cref="PropertyValueAttribute"/> object.</returns>
310283
public IEnumerable<PropertyValueAttribute> GetPropertyValueAttributes()
311284
{
312-
if (isPropertyValueAttributesWasSet == true)
313-
{
314-
return propertyValueAttributes;
315-
}
316-
isPropertyValueAttributesWasSet = true;
317-
return propertyValueAttributes = PropertyInfo.GetPropertyValueAttributes(GetDeclaringType());
285+
return propertyValueAttributes.Value;
318286
}
319287

320288
#endregion

RepoDb.Core/RepoDb/Extensions/TypeExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public static int GenerateHashCode(Type type) =>
241241
/// <returns>The generated hashcode.</returns>
242242
public static int GenerateHashCode(Type entityType,
243243
PropertyInfo propertyInfo) =>
244-
entityType.GetHashCode() + propertyInfo.GenerateCustomizedHashCode(entityType);
244+
HashCode.Combine(entityType.GetHashCode(), propertyInfo.GenerateCustomizedHashCode(entityType));
245245

246246
/// <summary>
247247
/// A helper method to return the instance of <see cref="PropertyInfo"/> object based on name.

RepoDb.Core/RepoDb/Reflection/Compiler/Compiler.cs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Data;
44
using System.Data.Common;
@@ -503,23 +503,30 @@ internal static PropertyInfo GetDateTimeTimeOfDayProperty() =>
503503
/// <returns></returns>
504504
internal static MethodInfo GetDateTimeTimeOfDayPropertyGetMethod() =>
505505
GetDateTimeTimeOfDayProperty().GetMethod;
506-
506+
#if NET6_0_OR_GREATER
507507
/// <summary>
508-
///
508+
///
509+
/// </summary>
510+
/// <returns></returns>
511+
internal static MethodInfo GetDateOnlyFromDateTimeStaticMethod() =>
512+
StaticType.DateOnly.GetMethod("FromDateTime");
513+
#endif
514+
/// <summary>
515+
///
509516
/// </summary>
510517
/// <returns></returns>
511518
internal static MethodInfo GetEnumParseMethod() =>
512519
StaticType.Enum.GetMethod("Parse", new[] { StaticType.Type, StaticType.String, StaticType.Boolean });
513520

514521
/// <summary>
515-
///
522+
///
516523
/// </summary>
517524
/// <returns></returns>
518525
internal static MethodInfo GetEnumGetNameMethod() =>
519526
StaticType.Enum.GetMethod("GetName", new[] { StaticType.Type, StaticType.Object });
520527

521528
/// <summary>
522-
///
529+
///
523530
/// </summary>
524531
/// <returns></returns>
525532
internal static MethodInfo GetEnumIsDefinedMethod() =>
@@ -587,7 +594,15 @@ internal static Expression ConvertExpressionToTimeSpanToDateTimeExpression(Expre
587594
/// <returns></returns>
588595
internal static Expression ConvertExpressionToDateTimeToTimeSpanExpression(Expression expression) =>
589596
ConvertExpressionToNullableGetValueOrDefaultExpression(ConvertExpressionToDateTimeTimeOfDayExpression(expression));
590-
597+
#if NET6_0_OR_GREATER
598+
/// <summary>
599+
///
600+
/// </summary>
601+
/// <param name="expression"></param>
602+
/// <returns></returns>
603+
internal static Expression ConvertExpressionToDateTimeToDateOnlyExpression(Expression expression) =>
604+
ConvertExpressionToNullableGetValueOrDefaultExpression(ConvertExpressionToDateOnlyFromDateTimeExpression(expression));
605+
#endif
591606
/// <summary>
592607
///
593608
/// </summary>
@@ -603,7 +618,15 @@ internal static Expression ConvertExpressionToTimeSpanTicksExpression(Expression
603618
/// <returns></returns>
604619
internal static Expression ConvertExpressionToDateTimeTimeOfDayExpression(Expression expression) =>
605620
Expression.Call(expression, GetDateTimeTimeOfDayPropertyGetMethod());
606-
621+
#if NET6_0_OR_GREATER
622+
/// <summary>
623+
///
624+
/// </summary>
625+
/// <param name="expression"></param>
626+
/// <returns></returns>
627+
internal static Expression ConvertExpressionToDateOnlyFromDateTimeExpression(Expression expression) =>
628+
Expression.Call(null, GetDateOnlyFromDateTimeStaticMethod(), expression);
629+
#endif
607630
/// <summary>
608631
///
609632
/// </summary>
@@ -878,7 +901,13 @@ internal static Expression ConvertExpressionWithAutomaticConversion(Expression e
878901
{
879902
expression = ConvertExpressionToDateTimeToTimeSpanExpression(expression);
880903
}
881-
904+
#if NET6_0_OR_GREATER
905+
// DateTime to DateOnly
906+
else if (fromType == StaticType.DateTime && toType == StaticType.DateOnly)
907+
{
908+
expression = ConvertExpressionToDateTimeToDateOnlyExpression(expression);
909+
}
910+
#endif
882911
// Others
883912
else
884913
{
@@ -1055,12 +1084,12 @@ internal static Expression ConvertExpressionToClassHandlerSetExpression(Expressi
10551084
return entityOrEntitiesExpression;
10561085
}
10571086

1058-
#endregion
1087+
#endregion
10591088

10601089
#region Common
10611090

10621091
/// <summary>
1063-
///
1092+
///
10641093
/// </summary>
10651094
/// <param name="expression"></param>
10661095
/// <param name="enumType"></param>
@@ -1080,7 +1109,7 @@ internal static Expression GetEnumParseExpression(Expression expression,
10801109
}
10811110

10821111
/// <summary>
1083-
///
1112+
///
10841113
/// </summary>
10851114
/// <param name="expression"></param>
10861115
/// <param name="enumType"></param>
@@ -1097,7 +1126,7 @@ internal static Expression GetEnumIsDefinedExpression(Expression expression,
10971126
}
10981127

10991128
/// <summary>
1100-
///
1129+
///
11011130
/// </summary>
11021131
/// <param name="expression"></param>
11031132
/// <param name="enumType"></param>
@@ -1215,6 +1244,9 @@ internal static Expression GetClassPropertyParameterInfoIsDbNullFalseValueExpres
12151244
var targetTypeUnderlyingType = TypeCache.Get(targetType).GetUnderlyingType();
12161245
var isAutomaticConversion = GlobalConfiguration.Options.ConversionType == ConversionType.Automatic ||
12171246
targetTypeUnderlyingType == StaticType.TimeSpan ||
1247+
#if NET6_0_OR_GREATER
1248+
targetTypeUnderlyingType == StaticType.DateOnly ||
1249+
#endif
12181250
/* SQLite: Guid/String (Vice-Versa) : Enforce automatic conversion for the Primary/Identity fields */
12191251
readerField.DbField?.IsPrimary == true || readerField.DbField?.IsIdentity == true;
12201252

RepoDb.Core/RepoDb/Reflection/Compiler/DataReaderToType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Data.Common;
33
using System.Linq.Expressions;
44
using System.Linq;

RepoDb.Core/RepoDb/Reflection/Compiler/PlainTypeToDbParameters.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,28 @@ internal static Action<DbCommand, object> GetPlainTypeToDbParametersCompiledFunc
8989
var dbType = (DbType?)null;
9090
if (valueType.IsEnum)
9191
{
92-
dbType = IsPostgreSqlUserDefined(dbField) ? default :
93-
paramProperty.GetDbType() ??
94-
valueType.GetDbType() ??
95-
(dbField != null ? new ClientTypeToDbTypeResolver().Resolve(dbField.Type) : null) ??
96-
(DbType?)GlobalConfiguration.Options.EnumDefaultDatabaseType;
92+
/*
93+
* Note: The other data provider can coerce the Enum into its destination data type in the DB by default,
94+
* except for PostgreSQL. The code written below is only to address the issue for this specific provider.
95+
*/
96+
97+
if (!IsPostgreSqlUserDefined(dbField))
98+
{
99+
dbType = paramProperty.GetDbType() ??
100+
valueType.GetDbType() ??
101+
(dbField != null ? new ClientTypeToDbTypeResolver().Resolve(dbField.Type) : null) ??
102+
(DbType?)GlobalConfiguration.Options.EnumDefaultDatabaseType;
103+
104+
if (GlobalConfiguration.Options.ConversionType == ConversionType.Automatic)
105+
{
106+
var toType = dbType.HasValue ? new DbTypeToClientTypeResolver().Resolve(dbType.Value) : TypeCache.Get(valueType)?.GetUnderlyingType();
107+
valueExpression = ConvertEnumExpressionToTypeExpression(valueExpression, toType);
108+
}
109+
}
110+
else
111+
{
112+
dbType = default;
113+
}
97114
}
98115
else
99116
{

0 commit comments

Comments
 (0)