Skip to content

Commit

Permalink
Merge pull request #133 from pvictorlv/master
Browse files Browse the repository at this point in the history
Fixes and Performance
  • Loading branch information
phnx47 authored Feb 28, 2020
2 parents fa270dc + dd98534 commit 41dc525
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 44 deletions.
33 changes: 30 additions & 3 deletions src/MicroOrm.Dapper.Repositories/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;
using MicroOrm.Dapper.Repositories.Attributes;
using MicroOrm.Dapper.Repositories.SqlGenerator;

namespace MicroOrm.Dapper.Repositories.Extensions
Expand All @@ -11,14 +13,17 @@ internal static class TypeExtensions
{
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> _reflectionPropertyCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> _reflectionPrimitivePropertyCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
private static readonly ConcurrentDictionary<Type, SqlPropertyMetadata[]> _metaDataPropertyCache = new ConcurrentDictionary<Type, SqlPropertyMetadata[]>();

public static PropertyInfo[] FindClassProperties(this Type objectType)
{
if (_reflectionPropertyCache.TryGetValue(objectType, out var cachedEntry))
return cachedEntry;

var propertyInfos = objectType.GetProperties()
.OrderBy(p => p.GetCustomAttributes<ColumnAttribute>()
.OrderByDescending(x => x.GetCustomAttribute<IdentityAttribute>() != null)
.ThenByDescending(x => x.GetCustomAttribute<KeyAttribute>() != null)
.ThenBy(p => p.GetCustomAttributes<ColumnAttribute>()
.Select(a => a.Order)
.DefaultIfEmpty(int.MaxValue)
.FirstOrDefault()).ToArray();
Expand All @@ -33,14 +38,36 @@ public static PropertyInfo[] FindClassPrimitiveProperties(this Type objectType)
if (_reflectionPrimitivePropertyCache.TryGetValue(objectType, out var cachedEntry))
return cachedEntry;

var propertyInfos = objectType.GetProperties()
.OrderBy(p => p.GetCustomAttributes<ColumnAttribute>()
var props = objectType.GetProperties();
var propertyInfos = props
.OrderByDescending(x => x.GetCustomAttribute<IdentityAttribute>() != null)
.ThenByDescending(x => x.GetCustomAttribute<KeyAttribute>() != null)
.ThenBy(p => p.GetCustomAttributes<ColumnAttribute>()
.Select(a => a.Order)
.DefaultIfEmpty(int.MaxValue)
.FirstOrDefault()).Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();

_reflectionPrimitivePropertyCache.TryAdd(objectType, propertyInfos);

return propertyInfos;
}
public static SqlPropertyMetadata[] FindClassMetaDataProperties(this Type objectType)
{
if (_metaDataPropertyCache.TryGetValue(objectType, out var cachedEntry))
return cachedEntry;

var props = objectType.GetProperties();
var propertyInfos = props
.OrderByDescending(x => x.GetCustomAttribute<IdentityAttribute>() != null)
.ThenByDescending(x => x.GetCustomAttribute<KeyAttribute>() != null)
.ThenBy(p => p.GetCustomAttributes<ColumnAttribute>()
.Select(a => a.Order)
.DefaultIfEmpty(int.MaxValue)
.FirstOrDefault()).Where(ExpressionHelper.GetPrimitivePropertiesPredicate())
.Where(p => !p.GetCustomAttributes<NotMappedAttribute>().Any()).Select(p => new SqlPropertyMetadata(p)).ToArray();

_metaDataPropertyCache.TryAdd(objectType, propertyInfos);

return propertyInfos;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ private SqlQuery InitBuilderSelect(bool firstOnly, FilterData filterData)
}
}

query.SqlBuilder.Append(filterData?.SelectInfo?.Columns == null ? GetFieldsSelect(TableName, SqlProperties) : GetFieldsSelect(filterData.SelectInfo.Columns));
query.SqlBuilder.Append(filterData?.SelectInfo?.Columns == null ? GetFieldsSelect(TableName, SqlProperties, UseQuotationMarks) : GetFieldsSelect(filterData.SelectInfo.Columns));

return query;
}
Expand All @@ -262,14 +262,14 @@ private static string GetFieldsSelect(List<string> properties)
return string.Join(", ", properties);
}

private static string GetFieldsSelect(string tableName, IEnumerable<SqlPropertyMetadata> properties)
private static string GetFieldsSelect(string tableName, IEnumerable<SqlPropertyMetadata> properties, bool useQuotation)
{
//Projection function
string ProjectionFunction(SqlPropertyMetadata p)
{
return !string.IsNullOrEmpty(p.Alias)
? $"{tableName}.{p.ColumnName} AS {p.PropertyName}"
: $"{tableName}.{p.ColumnName}";
? $"{tableName}.{(useQuotation ? p.ColumnName : p.CleanColumnName)} AS {p.PropertyName}"
: $"{tableName}.{(useQuotation ? p.ColumnName : p.CleanColumnName)}";
}

return string.Join(", ", properties.Select(ProjectionFunction));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ public virtual SqlQuery GetUpdate(TEntity entity, params Expression<Func<TEntity
{
var joinsBuilder = AppendJoinToUpdate(entity, query, includes);
query.SqlBuilder.Append("SET ");
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties));
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties, UseQuotationMarks));
query.SqlBuilder.Append(joinsBuilder);
}
else
{
query.SqlBuilder.Append("SET ");
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties));
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties, UseQuotationMarks));
}

query.SqlBuilder.Append(" WHERE ");
Expand Down Expand Up @@ -102,13 +102,13 @@ public virtual SqlQuery GetUpdate(Expression<Func<TEntity, bool>> predicate, TEn
{
var joinsBuilder = AppendJoinToUpdate(entity, query, includes);
query.SqlBuilder.Append("SET ");
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties));
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties, UseQuotationMarks));
query.SqlBuilder.Append(joinsBuilder);
}
else
{
query.SqlBuilder.Append("SET ");
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties));
query.SqlBuilder.Append(GetFieldsUpdate(TableName, properties, UseQuotationMarks));
}

query.SqlBuilder
Expand All @@ -123,10 +123,10 @@ public virtual SqlQuery GetUpdate(Expression<Func<TEntity, bool>> predicate, TEn
return query;
}

private static string GetFieldsUpdate(string tableName, IEnumerable<SqlPropertyMetadata> properties)
private static string GetFieldsUpdate(string tableName, IEnumerable<SqlPropertyMetadata> properties, bool useMarks)
{
return string.Join(", ", properties
.Select(p => $"{tableName}.{p.ColumnName} = @{p.PropertyInfo.DeclaringType.Name}{p.PropertyName}"));
.Select(p => $"{tableName}.{(useMarks ? p.ColumnName : p.CleanColumnName)} = @{p.PropertyInfo.ReflectedType.Name}{p.PropertyName}"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,20 @@ private void InitMetaData(string startQuotationMark, string endQuotationMark)
TableName = GetTableNameWithSchemaPrefix(TableName, TableSchema, startQuotationMark, endQuotationMark);

foreach (var propertyMetadata in SqlProperties)
propertyMetadata.ColumnName = startQuotationMark + propertyMetadata.ColumnName + endQuotationMark;
propertyMetadata.ColumnName = startQuotationMark + propertyMetadata.CleanColumnName + endQuotationMark;

foreach (var propertyMetadata in KeySqlProperties)
propertyMetadata.ColumnName = startQuotationMark + propertyMetadata.ColumnName + endQuotationMark;
propertyMetadata.ColumnName = startQuotationMark + propertyMetadata.CleanColumnName + endQuotationMark;

foreach (var propertyMetadata in SqlJoinProperties)
{
propertyMetadata.TableName = GetTableNameWithSchemaPrefix(propertyMetadata.TableName, propertyMetadata.TableSchema, startQuotationMark, endQuotationMark);
propertyMetadata.ColumnName = startQuotationMark + propertyMetadata.ColumnName + endQuotationMark;
propertyMetadata.ColumnName = startQuotationMark + propertyMetadata.CleanColumnName + endQuotationMark;
propertyMetadata.TableAlias = string.IsNullOrEmpty(propertyMetadata.TableAlias) ? string.Empty : startQuotationMark + propertyMetadata.TableAlias + endQuotationMark;
}

if (IdentitySqlProperty != null)
IdentitySqlProperty.ColumnName = startQuotationMark + IdentitySqlProperty.ColumnName + endQuotationMark;
IdentitySqlProperty.ColumnName = startQuotationMark + IdentitySqlProperty.CleanColumnName + endQuotationMark;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private void InitProperties()

AllProperties = entityType.FindClassProperties().Where(q => q.CanWrite).ToArray();

var props = AllProperties.Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();
var props = entityType.FindClassPrimitiveProperties();

var joinProperties = AllProperties.Where(p => p.GetCustomAttributes<JoinAttributeBase>().Any()).ToArray();

Expand Down
46 changes: 22 additions & 24 deletions src/MicroOrm.Dapper.Repositories/SqlGenerator/SqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ private static SqlJoinPropertyMetadata[] GetJoinPropertyMetadata(PropertyInfo[]
foreach (var propertyInfo in singleJoinTypes)
{
var joinInnerProperties = propertyInfo.PropertyType.GetProperties().Where(q => q.CanWrite)
.Where(ExpressionHelper.GetPrimitivePropertiesPredicate()).ToArray();
.Where(ExpressionHelper.GetPrimitivePropertiesPredicate());
joinPropertyMetadatas.AddRange(joinInnerProperties.Where(p => !p.GetCustomAttributes<NotMappedAttribute>().Any())
.Select(p => new SqlJoinPropertyMetadata(propertyInfo, p)).ToArray());
}
Expand All @@ -310,7 +310,10 @@ private string GetTableNameWithQuotes(JoinAttributeBase attrJoin, SqlPropertyMet
attrJoin.ExternalKey = "[" + attrJoin.ExternalKey + "]";
attrJoin.TableAlias = string.IsNullOrEmpty(attrJoin.TableAlias) ? string.Empty : "[" + attrJoin.TableAlias + "]";
foreach (var prop in props)
prop.ColumnName = "[" + prop.ColumnName + "]";
{
prop.ColumnName = "[" + prop.CleanColumnName + "]";
}

break;

case SqlProvider.MySQL:
Expand All @@ -320,7 +323,10 @@ private string GetTableNameWithQuotes(JoinAttributeBase attrJoin, SqlPropertyMet
attrJoin.ExternalKey = "`" + attrJoin.ExternalKey + "`";
attrJoin.TableAlias = string.IsNullOrEmpty(attrJoin.TableAlias) ? string.Empty : "`" + attrJoin.TableAlias + "`";
foreach (var prop in props)
prop.ColumnName = "`" + prop.ColumnName + "`";
{
prop.ColumnName = "`" + prop.CleanColumnName + "`";
}

break;

case SqlProvider.SQLite:
Expand All @@ -333,7 +339,10 @@ private string GetTableNameWithQuotes(JoinAttributeBase attrJoin, SqlPropertyMet
attrJoin.ExternalKey = "\"" + attrJoin.ExternalKey + "\"";
attrJoin.TableAlias = string.IsNullOrEmpty(attrJoin.TableAlias) ? string.Empty : "\"" + attrJoin.TableAlias + "\"";
foreach (var prop in props)
prop.ColumnName = "\"" + prop.ColumnName + "\"";
{
prop.ColumnName = "\"" + prop.CleanColumnName + "\"";
}

break;

default:
Expand All @@ -355,32 +364,29 @@ private string AppendJoinToUpdate<TBase>(TBase entity, SqlQuery originalBuilder,
if (attrJoin == null)
continue;

var declaringType = joinProperty.DeclaringType.GetTypeInfo();
var declaringType = joinProperty.ReflectedType.GetTypeInfo();
var tableAttribute = declaringType.GetCustomAttribute<TableAttribute>();
var tableName = MicroOrmConfig.TablePrefix + (tableAttribute != null ? tableAttribute.Name : declaringType.Name);

var joinType = joinProperty.PropertyType.IsGenericType ? joinProperty.PropertyType.GenericTypeArguments[0] : joinProperty.PropertyType;
var properties = joinType.FindClassPrimitiveProperties();
SqlPropertyMetadata[] props = properties
.Where(p => !p.GetCustomAttributes<NotMappedAttribute>().Any() && !p.GetCustomAttributes<IgnoreUpdateAttribute>().Any() &&
p.GetCustomAttribute<KeyAttribute>() == null).Select(p => new SqlPropertyMetadata(p)).ToArray();
var properties = joinType.FindClassMetaDataProperties().Where(p=> !p.IgnoreUpdate).ToArray();

var joinEntity = entity.GetType().GetProperty(joinProperty.Name).GetValue(entity, null);
if (joinEntity == null)
return string.Empty;

var dict = props.ToDictionary(prop => $"{prop.PropertyInfo.DeclaringType.Name}{prop.PropertyName}",
var dict = properties.ToDictionary(prop => $"{prop.PropertyInfo.ReflectedType.Name}{prop.PropertyName}",
prop => joinType.GetProperty(prop.PropertyName).GetValue(joinEntity, null));
originalBuilder.SetParam(dict);

if (UseQuotationMarks)
{
tableName = GetTableNameWithQuotes(attrJoin, props, tableName);
tableName = GetTableNameWithQuotes(attrJoin, properties, tableName);
}
else
attrJoin.TableName = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema);

joinBuilder.Append($", {GetFieldsUpdate(string.IsNullOrEmpty(attrJoin.TableAlias) ? attrJoin.TableName : attrJoin.TableAlias, props)}");
joinBuilder.Append($", {GetFieldsUpdate(string.IsNullOrEmpty(attrJoin.TableAlias) ? attrJoin.TableName : attrJoin.TableAlias, properties, UseQuotationMarks)}");
AppendJoinQuery(attrJoin, originalBuilder.SqlBuilder, tableName);
}

Expand Down Expand Up @@ -438,30 +444,22 @@ private string AppendJoinToSelect(SqlQuery originalBuilder, bool hasSelectFilter
if (attrJoin == null)
continue;

var declaringType = joinProperty.DeclaringType.GetTypeInfo();
var declaringType = joinProperty.ReflectedType.GetTypeInfo();
var tableAttribute = declaringType.GetCustomAttribute<TableAttribute>();
var tableName = MicroOrmConfig.TablePrefix + (tableAttribute != null ? tableAttribute.Name : declaringType.Name);

var joinType = joinProperty.PropertyType.IsGenericType ? joinProperty.PropertyType.GenericTypeArguments[0] : joinProperty.PropertyType;
var properties = joinType.FindClassPrimitiveProperties();
SqlPropertyMetadata[] props = null;
var properties = joinType.FindClassMetaDataProperties();

if (UseQuotationMarks || !hasSelectFilter)
props = properties.Where(p => !p.GetCustomAttributes<NotMappedAttribute>().Any())
.OrderByDescending(x=> x.GetCustomAttribute<IdentityAttribute>() != null)
.ThenBy(x=> x.GetCustomAttribute<KeyAttribute>() != null)
.ThenBy(x=> x.GetCustomAttribute<ColumnAttribute>() != null ? x.GetCustomAttribute<ColumnAttribute>().Order : properties.Length)
.Select(p => new SqlPropertyMetadata(p)).ToArray();

if (UseQuotationMarks)
{
tableName = GetTableNameWithQuotes(attrJoin, props, tableName);
tableName = GetTableNameWithQuotes(attrJoin, properties, tableName);
}
else
attrJoin.TableName = GetTableNameWithSchemaPrefix(attrJoin.TableName, attrJoin.TableSchema);

if (!hasSelectFilter)
originalBuilder.SqlBuilder.Append($", {GetFieldsSelect(string.IsNullOrEmpty(attrJoin.TableAlias) ? attrJoin.TableName : attrJoin.TableAlias, props)}");
originalBuilder.SqlBuilder.Append($", {GetFieldsSelect(string.IsNullOrEmpty(attrJoin.TableAlias) ? attrJoin.TableName : attrJoin.TableAlias, properties, UseQuotationMarks)}");

AppendJoinQuery(attrJoin, joinBuilder, tableName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public SqlPropertyMetadata(PropertyInfo propertyInfo)
{
ColumnName = PropertyInfo.Name;
}

CleanColumnName = ColumnName;

var ignoreUpdate = PropertyInfo.GetCustomAttribute<IgnoreUpdateAttribute>();
if (ignoreUpdate != null)
IgnoreUpdate = true;
Expand All @@ -44,6 +47,11 @@ public SqlPropertyMetadata(PropertyInfo propertyInfo)
/// ColumnName
/// </summary>
public string ColumnName { get; set; }

/// <summary>
/// ColumnName
/// </summary>
public string CleanColumnName { get; set; }

/// <summary>
/// Exclude property from update
Expand All @@ -55,4 +63,4 @@ public SqlPropertyMetadata(PropertyInfo propertyInfo)
/// </summary>
public virtual string PropertyName => PropertyInfo.Name;
}
}
}
2 changes: 1 addition & 1 deletion test/MicroOrm.Dapper.Repositories.Tests/Classes/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace MicroOrm.Dapper.Repositories.Tests.Classes
public class Address
{
[Key]
[Identity]
[Identity, IgnoreUpdate]
public int Id { get; set; }

public string Street { get; set; }
Expand Down

0 comments on commit 41dc525

Please sign in to comment.