Skip to content

Commit 153c1c4

Browse files
Merge pull request #76 from johelvisguzman/adonet-annotations
Added changes to support data annotations for the ado-net repository
2 parents 4035d25 + a91f39e commit 153c1c4

File tree

13 files changed

+452
-130
lines changed

13 files changed

+452
-130
lines changed

src/DotNetToolkit.Repository.AdoNet/AdoNetRepositoryBase.cs

Lines changed: 66 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ public abstract class AdoNetRepositoryBase<TEntity, TKey> : RepositoryAsyncBase<
5050
/// <summary>
5151
/// Gets the name of the identity property.
5252
/// </summary>
53-
protected PropertyInfo SqlIdentityProperty { get; private set; }
53+
protected PropertyInfo SqlIdentityPropertyInfo { get; private set; }
5454

5555
/// <summary>
5656
/// Gets the SQL properties.
5757
/// </summary>
58-
protected Dictionary<string, PropertyInfo> SqlProperties { get; private set; }
58+
protected Dictionary<string, PropertyInfo> SqlPropertiesMapping { get; private set; }
5959

6060
/// <summary>
6161
/// Gets the name of the table.
@@ -1301,12 +1301,13 @@ protected virtual IEnumerable<IGrouping<TGroupKey, TElement>> ExecuteGroup<TGrou
13011301

13021302
private void Initialize()
13031303
{
1304-
SqlProperties = typeof(TEntity)
1304+
SqlPropertiesMapping = typeof(TEntity)
13051305
.GetRuntimeProperties()
1306-
.Where(x => x.PropertyType.Namespace == "System")
1307-
.ToDictionary(x => x.Name, x => x);
1306+
.Where(x => x.IsPrimitive() && x.IsMapped())
1307+
.OrderBy(x => x.GetColumnOrder())
1308+
.ToDictionary(ConventionHelper.GetColumnName, x => x);
13081309

1309-
TableName = $"{typeof(TEntity).Name}";
1310+
TableName = typeof(TEntity).GetTableName();
13101311

13111312
DataRow autoIncrementDataRow = null;
13121313

@@ -1326,8 +1327,14 @@ private void Initialize()
13261327

13271328
if (autoIncrementDataRow != null)
13281329
{
1330+
var columnName = (string)autoIncrementDataRow["ColumnName"];
1331+
1332+
SqlIdentityPropertyInfo = SqlPropertiesMapping.FirstOrDefault(x => x.Key.Equals(columnName)).Value;
1333+
1334+
if (SqlIdentityPropertyInfo == null)
1335+
throw new InvalidOperationException(string.Format(Resources.InvalidColumnName, columnName));
1336+
13291337
IsIdentity = true;
1330-
SqlIdentityProperty = SqlProperties.Select(x => x.Value).First(x => x.Name.Equals((string)autoIncrementDataRow["ColumnName"]));
13311338
}
13321339
}
13331340
}
@@ -1338,19 +1345,18 @@ private void PrepareSelectStatement(IFetchStrategy<TEntity> fetchStrategy, out D
13381345
var cfg = new DbSqlSelectStatementConfig();
13391346

13401347
var mainTableType = typeof(TEntity);
1341-
var mainTableAlias = cfg.GenerateTableAlias(mainTableType, TableName);
1348+
var mainTableAlias = cfg.GenerateTableAlias(mainTableType);
13421349
var mainTableProperties = mainTableType.GetRuntimeProperties();
1343-
var mainTablePrimaryKeyName = GetPrimaryKeyPropertyInfo().Name;
1344-
1345-
const string systemNameSpace = "System";
1350+
var mainTablePrimaryKeyName = typeof(TEntity).GetPrimaryKeyPropertyInfo().GetColumnName();
13461351

13471352
// Default select
13481353
var selectSql = string.Join(",\n\t",
1349-
SqlProperties.Select(x =>
1354+
SqlPropertiesMapping.Select(x =>
13501355
{
1351-
cfg.GenerateColumnAlias(TableName, x.Key);
1356+
var colAlias = cfg.GenerateColumnAlias(x.Value);
1357+
var colName = x.Value.GetColumnName();
13521358

1353-
return $"[{mainTableAlias}].[{x.Key}] AS [{x.Key}]";
1359+
return $"[{mainTableAlias}].[{colName}] AS [{colAlias}]";
13541360
}));
13551361

13561362
// Check to see if we can automatically include some navigation properties (this seems to be the behavior of entity framework as well).
@@ -1360,15 +1366,9 @@ private void PrepareSelectStatement(IFetchStrategy<TEntity> fetchStrategy, out D
13601366
// Assumes we want to perform a join when the navigation property from the primary table has also a navigation property of
13611367
// the same type as the primary table
13621368
// Only do a join when the primary table has a foreign key property for the join table
1363-
var paths = (
1364-
from pi in mainTableProperties.Where(x => x.PropertyType.Namespace != systemNameSpace)
1365-
let jointTableType = pi.PropertyType
1366-
let joinTableProperties = jointTableType.GetRuntimeProperties()
1367-
where joinTableProperties.Any(x => x.PropertyType == mainTableType)
1368-
let joinTableForeignKeyName = joinTableProperties.SingleOrDefault(x => x.Name == $"{TableName}{mainTablePrimaryKeyName}")?.Name
1369-
where !string.IsNullOrEmpty(joinTableForeignKeyName)
1370-
select pi.Name
1371-
)
1369+
var paths = mainTableProperties
1370+
.Where(x => x.IsComplex() && !string.IsNullOrEmpty(x.PropertyType.GetForeignKeyName(mainTableType)))
1371+
.Select(x => x.Name)
13721372
.ToList();
13731373

13741374
if (paths.Count > 0)
@@ -1394,39 +1394,34 @@ select pi.Name
13941394
foreach (var path in fetchStrategy.IncludePaths)
13951395
{
13961396
var joinTablePropertyInfo = mainTableProperties.Single(x => x.Name.Equals(path));
1397-
var jointTableType = joinTablePropertyInfo.PropertyType;
1398-
var joinTableProperties = jointTableType.GetRuntimeProperties();
1397+
var joinTableType = joinTablePropertyInfo.PropertyType;
1398+
var joinTableForeignKeyName = joinTableType.GetForeignKeyName(mainTableType);
13991399

1400-
// Assumes we want to perform a join when the navigation property from the primary table has also a navigation property of
1401-
// the same type as the primary table
1402-
if (joinTableProperties.Any(x => x.PropertyType == mainTableType))
1400+
// Only do a join when the primary table has a foreign key property for the join table
1401+
if (!string.IsNullOrEmpty(joinTableForeignKeyName))
14031402
{
1404-
var joinTableForeignKeyName = joinTableProperties.SingleOrDefault(x => x.Name == $"{TableName}{mainTablePrimaryKeyName}")?.Name;
1403+
var joinTableProperties = joinTableType.GetRuntimeProperties();
1404+
var joinTableName = joinTableType.GetTableName();
1405+
var joinTableAlias = cfg.GenerateTableAlias(joinTableType);
1406+
var joinTableColumnNames = string.Join(",\n\t",
1407+
joinTableProperties
1408+
.Where(x => x.IsPrimitive())
1409+
.Select(x =>
1410+
{
1411+
var colAlias = cfg.GenerateColumnAlias(x);
1412+
var colName = x.GetColumnName();
14051413

1406-
// Only do a join when the primary table has a foreign key property for the join table
1407-
if (!string.IsNullOrEmpty(joinTableForeignKeyName))
1408-
{
1409-
var joinTableName = $"{joinTablePropertyInfo.PropertyType.Name}";
1410-
var joinTableAlias = cfg.GenerateTableAlias(joinTablePropertyInfo.PropertyType, joinTableName);
1411-
var joinTableColumnNames = string.Join(",\n\t",
1412-
joinTableProperties
1413-
.Where(x => x.PropertyType.Namespace == systemNameSpace)
1414-
.Select(x =>
1415-
{
1416-
var colAlias = cfg.GenerateColumnAlias(joinTableName, x.Name);
1417-
1418-
return $"[{joinTableAlias}].[{x.Name}] AS [{colAlias}]";
1419-
}));
1414+
return $"[{joinTableAlias}].[{colName}] AS [{colAlias}]";
1415+
}));
14201416

14211417

1422-
sb.Append(",\n\t");
1423-
sb.Append(joinTableColumnNames);
1418+
sb.Append(",\n\t");
1419+
sb.Append(joinTableColumnNames);
14241420

1425-
joinStatementSb.Append("\n");
1426-
joinStatementSb.Append($"LEFT OUTER JOIN [{joinTableName}] AS [{joinTableAlias}] ON [{mainTableAlias}].[{mainTablePrimaryKeyName}] = [{joinTableAlias}].[{joinTableForeignKeyName}]");
1421+
joinStatementSb.Append("\n");
1422+
joinStatementSb.Append($"LEFT OUTER JOIN [{joinTableName}] AS [{joinTableAlias}] ON [{mainTableAlias}].[{mainTablePrimaryKeyName}] = [{joinTableAlias}].[{joinTableForeignKeyName}]");
14271423

1428-
cfg.JoinTablePropertiesMapping.Add(jointTableType, joinTableProperties.ToDictionary(x => x.Name, x => x));
1429-
}
1424+
cfg.JoinTablePropertiesMapping.Add(joinTableType, joinTableProperties.ToDictionary(x => x.GetColumnName(), x => x));
14301425
}
14311426
}
14321427

@@ -1480,8 +1475,8 @@ private void PrepareSelectStatement(ISpecification<TEntity> criteria, IQueryOpti
14801475
var tableType = ExpressionHelper.GetMemberExpression(lambda).Expression.Type;
14811476
var tableName = config.GetTableName(tableType);
14821477
var tableAlias = config.GetTableAlias(tableName);
1483-
var sortingPropertyName = ExpressionHelper.GetPropertyName(lambda);
1484-
var columnAlias = config.GetColumnAlias(tableName, sortingPropertyName);
1478+
var sortingPropertyInfo = ExpressionHelper.GetPropertyInfo(lambda);
1479+
var columnAlias = config.GetColumnAlias(sortingPropertyInfo);
14851480

14861481
sb.Append("\n");
14871482
sb.Append(sortingOptions.IsDescending ? $"ORDER BY [{tableAlias}].[{columnAlias}] DESC" : $"ORDER BY [{tableAlias}].[{columnAlias}] ASC");
@@ -1502,7 +1497,8 @@ private void PrepareSelectStatement(ISpecification<TEntity> criteria, IQueryOpti
15021497

15031498
private void PrepareEntitySetStatement(EntitySet entitySet, out string sql, out Dictionary<string, object> parameters)
15041499
{
1505-
var properties = IsIdentity ? SqlProperties.Where(x => !x.Key.Equals(SqlIdentityProperty.Name)) : SqlProperties;
1500+
var primeryKeyColumnName = SqlIdentityPropertyInfo.GetColumnName();
1501+
var properties = IsIdentity ? SqlPropertiesMapping.Where(x => !x.Key.Equals(primeryKeyColumnName)) : SqlPropertiesMapping;
15061502

15071503
parameters = new Dictionary<string, object>();
15081504
sql = string.Empty;
@@ -1511,42 +1507,46 @@ private void PrepareEntitySetStatement(EntitySet entitySet, out string sql, out
15111507
{
15121508
case EntityState.Added:
15131509
{
1514-
var columnNames = string.Join(", ", properties.Select(x => x.Key)).TrimEnd();
1515-
var values = string.Join(",\n\t", properties.Select(x => $"@{x.Key}"));
1510+
var columnNames = string.Join(", ", properties.Select(x => x.Value.GetColumnName())).TrimEnd();
1511+
var values = string.Join(", ", properties.Select(x => $"@{x.Value.GetColumnName()}")).TrimEnd();
15161512

15171513
sql = $"INSERT INTO [{TableName}] ({columnNames})\nVALUES ({values})";
15181514

15191515
foreach (var pi in properties)
15201516
{
1521-
parameters.Add($"@{pi.Key}", pi.Value.GetValue(entitySet.Entity, null));
1517+
parameters.Add($"@{pi.Value.GetColumnName()}", pi.Value.GetValue(entitySet.Entity, null));
15221518
}
15231519

15241520
if (IsIdentity)
1525-
parameters.Add($"@{SqlIdentityProperty.Name}", SqlIdentityProperty.GetValue(entitySet.Entity, null));
1521+
parameters.Add($"@{primeryKeyColumnName}", SqlIdentityPropertyInfo.GetValue(entitySet.Entity, null));
15261522

15271523
break;
15281524
}
15291525
case EntityState.Removed:
15301526
{
1531-
sql = $"DELETE FROM [{TableName}]\nWHERE {SqlIdentityProperty.Name} = @{SqlIdentityProperty.Name}";
1527+
sql = $"DELETE FROM [{TableName}]\nWHERE {primeryKeyColumnName} = @{primeryKeyColumnName}";
15321528

1533-
parameters.Add($"@{SqlIdentityProperty.Name}", SqlIdentityProperty.GetValue(entitySet.Entity, null));
1529+
parameters.Add($"@{primeryKeyColumnName}", SqlIdentityPropertyInfo.GetValue(entitySet.Entity, null));
15341530

15351531
break;
15361532
}
15371533
case EntityState.Modified:
15381534
{
1539-
var values = string.Join(",\n\t", properties.Select(x => x.Key + " = " + $"@{x.Key}"));
1535+
var values = string.Join(",\n\t", properties.Select(x =>
1536+
{
1537+
var columnName = x.Value.GetColumnName();
1538+
return columnName + " = " + $"@{columnName}";
1539+
}));
15401540

1541-
sql = $"UPDATE [{TableName}]\nSET {values}\nWHERE {SqlIdentityProperty.Name} = @{SqlIdentityProperty.Name}";
1541+
sql = $"UPDATE [{TableName}]\nSET {values}\nWHERE {primeryKeyColumnName} = @{primeryKeyColumnName}";
15421542

15431543
foreach (var pi in properties)
15441544
{
1545-
parameters.Add($"@{pi.Key}", pi.Value.GetValue(entitySet.Entity, null));
1545+
parameters.Add($"@{pi.Value.GetColumnName()}", pi.Value.GetValue(entitySet.Entity, null));
15461546
}
15471547

15481548
if (IsIdentity)
1549-
parameters.Add($"@{SqlIdentityProperty.Name}", SqlIdentityProperty.GetValue(entitySet.Entity, null));
1549+
parameters.Add($"@{primeryKeyColumnName}", SqlIdentityPropertyInfo.GetValue(entitySet.Entity, null));
15501550

15511551
break;
15521552
}
@@ -1573,9 +1573,9 @@ private TElement AutoMap<TElement>(DbDataReader r, Expression<Func<TEntity, TEle
15731573
if (value == DBNull.Value)
15741574
value = null;
15751575

1576-
if (SqlProperties.ContainsKey(name) && !r.IsDBNull(r.GetOrdinal(name)))
1576+
if (SqlPropertiesMapping.ContainsKey(name) && !r.IsDBNull(r.GetOrdinal(name)))
15771577
{
1578-
SqlProperties[name].SetValue(entity, value);
1578+
SqlPropertiesMapping[name].SetValue(entity, value);
15791579
}
15801580
else if (joinTableInstances != null)
15811581
{
@@ -1672,7 +1672,7 @@ protected override void SaveChanges()
16721672
{
16731673
var key = ExecuteScalar<TKey>(connection, "SELECT @@IDENTITY");
16741674

1675-
SetPrimaryKey(entitySet.Entity, key);
1675+
entitySet.Entity.SetPrimaryKeyPropertyValue(key);
16761676
}
16771677
}
16781678

@@ -1853,7 +1853,7 @@ public override void Dispose()
18531853
{
18541854
var key = await ExecuteScalarAsync<TKey>(connection, "SELECT @@IDENTITY", null, cancellationToken);
18551855

1856-
SetPrimaryKey(entitySet.Entity, key);
1856+
entitySet.Entity.SetPrimaryKeyPropertyValue(key);
18571857
}
18581858
}
18591859

src/DotNetToolkit.Repository.AdoNet/Internal/DbSqlExpressionTranslator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,12 @@ private void TranslateMethodCall(MethodCallExpression node)
9898
variableExpression = secondExpression;
9999
}
100100

101-
var property = ExpressionHelper.GetPropertyName(variableExpression);
101+
var propertyInfo = ExpressionHelper.GetPropertyInfo(variableExpression);
102102
var value = ExpressionHelper.GetPropertyValue(constantExpression);
103103
var tableType = ExpressionHelper.GetMemberExpression(variableExpression).Expression.Type;
104104
var tableName = _config.GetTableName(tableType);
105105
var tableAlias = _config.GetTableAlias(tableName);
106-
var columnAlias = _config.GetColumnAlias(tableName, property);
106+
var columnAlias = _config.GetColumnAlias(propertyInfo);
107107

108108
_sb.Append($"[{tableAlias}].[{columnAlias}]");
109109

@@ -129,12 +129,12 @@ private void TranslateComparison(BinaryExpression node)
129129
{
130130
var variableExpression = node.Left;
131131
var constantExpression = node.Right as ConstantExpression;
132-
var property = ExpressionHelper.GetPropertyName(variableExpression);
132+
var propertyInfo = ExpressionHelper.GetPropertyInfo(variableExpression);
133133
var value = ExpressionHelper.GetPropertyValue(constantExpression);
134134
var tableType = ExpressionHelper.GetMemberExpression(variableExpression).Expression.Type;
135135
var tableName = _config.GetTableName(tableType);
136136
var tableAlias = _config.GetTableAlias(tableName);
137-
var columnAlias = _config.GetColumnAlias(tableName, property);
137+
var columnAlias = _config.GetColumnAlias(propertyInfo);
138138

139139
_sb.Append($"[{tableAlias}].[{columnAlias}]");
140140

src/DotNetToolkit.Repository.AdoNet/Internal/DbSqlSelectStatementConfig.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
namespace DotNetToolkit.Repository.AdoNet.Internal
22
{
3+
using Helpers;
4+
using Properties;
35
using System;
46
using System.Collections.Generic;
57
using System.Linq;
@@ -42,9 +44,10 @@ public DbSqlSelectStatementConfig()
4244

4345
#region Public Methods
4446

45-
public string GenerateTableAlias(Type tableType, string tableName)
47+
public string GenerateTableAlias(Type tableType)
4648
{
4749
var tableAlias = $"Extent{_tableAliasCount++}";
50+
var tableName = tableType.GetTableName();
4851

4952
_tableAliasMapping.Add(tableName, tableAlias);
5053
_tableNameAndTypeMapping.Add(tableName, tableType);
@@ -54,9 +57,11 @@ public string GenerateTableAlias(Type tableType, string tableName)
5457
return tableAlias;
5558
}
5659

57-
public string GenerateColumnAlias(string tableName, string columnName)
60+
public string GenerateColumnAlias(PropertyInfo pi)
5861
{
62+
var columnName = pi.GetColumnName();
5963
var columnAlias = columnName;
64+
var tableName = pi.DeclaringType.GetTableName();
6065

6166
if (_columnAliasMappingCount.TryGetValue(columnName, out int columnAliasCount))
6267
{
@@ -94,9 +99,16 @@ public string GetTableName(Type tableType)
9499
return _tableTypeAndNameMapping[tableType];
95100
}
96101

97-
public string GetColumnAlias(string tableName, string columnName)
102+
public string GetColumnAlias(PropertyInfo pi)
98103
{
99-
return _tableColumnAliasMapping[tableName][columnName];
104+
var columnName = pi.GetColumnName();
105+
var tableName = pi.DeclaringType.GetTableName();
106+
var columnMapping = _tableColumnAliasMapping[tableName];
107+
108+
if (!columnMapping.ContainsKey(columnName))
109+
throw new InvalidOperationException(string.Format(Resources.InvalidColumnName, columnName));
110+
111+
return columnMapping[columnName];
100112
}
101113

102114
public string GetColumnName(string columnAlias)

src/DotNetToolkit.Repository.AdoNet/Properties/Resources.Designer.cs

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/DotNetToolkit.Repository.AdoNet/Properties/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,7 @@
126126
<data name="ArgumentCannotBeNullOrEmptyString" xml:space="preserve">
127127
<value>Cannot be null or an empty string.</value>
128128
</data>
129+
<data name="InvalidColumnName" xml:space="preserve">
130+
<value>The column name {0} is not valid.</value>
131+
</data>
129132
</root>

0 commit comments

Comments
 (0)