There is an issue when using Expressions on base properties in derived types. For example:
public abstract class BaseClass
{ [Key]
public int Id { get; set; }
}
[Table("People.Person"]
public class Person : BaseClass
{ public` string Name { get;set;}
}
var result = await connection.SelectAsync<Person>(p => p.Name == model.Name && c.Id != model.Id);
Resolves to:
SELECT * FROM People.Person WHERE People.Person.Name = 'Bob' AND BaseClass.Id <> 1)
The column resolved in Resolvers is using PropertyInfo to derive the table name - this uses the ReflectedType which is the base type not the derived one.
My quick and dirty solution was to add the following to Resolvers.cs:
/// <summary>
/// Gets the name of the column in the database for the specified type,
/// using the configured <see cref="IColumnNameResolver"/>.
/// </summary>
/// <param name="expression">The <see cref="MemberExpression"/> to get the column name for.</param>
/// <param name="sqlBuilder">The SQL builder instance.</param>
/// <returns>The column name in the database for <paramref name="expression"/>.</returns>
public static string Column(MemberExpression expression, ISqlBuilder sqlBuilder)
=> Column(expression, sqlBuilder, DommelMapper.IncludeTableNameInColumnName);
/// <summary>
/// Gets the name of the column in the database for the specified type,
/// using the configured <see cref="IColumnNameResolver"/>.
/// </summary>
/// <param name="expression">The <see cref="MemberExpression"/> to get the column name for.</param>
/// <param name="sqlBuilder">The SQL builder instance.</param>
/// <param name="includeTableName">Whether to include table name with the column name for unambiguity. E.g. <c>[Products].[Name]</c>.</param>
/// <returns>The column name in the database for <paramref name="expression"/>.</returns>
public static string Column(MemberExpression expression, ISqlBuilder sqlBuilder, bool includeTableName = true)
{
var propertyInfo = (PropertyInfo) expression.Member;
var key = $"{sqlBuilder.GetType()}.{expression.Expression.Type}.{propertyInfo.Name}.{includeTableName}";
if (!ColumnNameCache.TryGetValue(key, out var columnName))
{
columnName = sqlBuilder.QuoteIdentifier(DommelMapper.ColumnNameResolver.ResolveColumnName(propertyInfo));
if (includeTableName && propertyInfo.ReflectedType?.IsDefined(typeof(CompilerGeneratedAttribute)) == false)
{
// Include the table name for unambiguity, except for anonymyes types e.g. x => new { x.Id, x.Name }
var tableName = Table(expression.Expression.Type, sqlBuilder);
columnName = $"{tableName}.{columnName}";
}
ColumnNameCache.TryAdd(key, columnName);
}
DommelMapper.LogReceived?.Invoke($"Resolved column name '{columnName}' for '{propertyInfo}'");
return columnName;
}
And call this from SqlExpression.cs:
/// <summary>
/// Proccesses a member expression.
/// </summary>
/// <param name="expression">The member expression.</param>
/// <returns>The result of the processing.</returns>
protected virtual string MemberToColumn(MemberExpression expression) =>
Resolvers.Column(expression, SqlBuilder);
There is an issue when using Expressions on base properties in derived types. For example:
var result = await connection.SelectAsync<Person>(p => p.Name == model.Name && c.Id != model.Id);
Resolves to:
SELECT * FROM People.Person WHERE People.Person.Name = 'Bob' AND BaseClass.Id <> 1)
The column resolved in Resolvers is using PropertyInfo to derive the table name - this uses the ReflectedType which is the base type not the derived one.
My quick and dirty solution was to add the following to Resolvers.cs:
And call this from SqlExpression.cs:
Not sure if this is the best solution!