Improve NPoco extensions
This commit is contained in:
@@ -7,7 +7,6 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
@@ -74,10 +73,27 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> Where<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, bool>> predicate, string alias = null)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<TDto>(sql.SqlContext, alias);
|
||||
var whereExpression = expresionist.Visit(predicate);
|
||||
sql.Where(whereExpression, expresionist.GetSqlParameters());
|
||||
return sql;
|
||||
var (s, a) = sql.SqlContext.Visit(predicate, alias);
|
||||
return sql.Where(s, a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends an AND clause to a WHERE Sql statement.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto">The type of the Dto.</typeparam>
|
||||
/// <param name="sql">The Sql statement.</param>
|
||||
/// <param name="predicate">A predicate to transform and append to the Sql statement.</param>
|
||||
/// <param name="alias">An optional alias for the table.</param>
|
||||
/// <returns>The Sql statement.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Chaining <c>.Where(...).Where(...)</c> in NPoco works because it merges the two WHERE statements,
|
||||
/// however if the first statement is not an explicit WHERE statement, chaining fails and two WHERE
|
||||
/// statements appear in the resulting Sql. This allows for adding an AND clause without problems.</para>
|
||||
/// </remarks>
|
||||
public static Sql<ISqlContext> AndWhere<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, bool>> predicate, string alias = null)
|
||||
{
|
||||
var (s, a) = sql.SqlContext.Visit(predicate, alias);
|
||||
return sql.Append("AND (" + s + ")", a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -92,10 +108,8 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> Where<TDto1, TDto2>(this Sql<ISqlContext> sql, Expression<Func<TDto1, TDto2, bool>> predicate, string alias1 = null, string alias2 = null)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<TDto1, TDto2>(sql.SqlContext, alias1, alias2);
|
||||
var whereExpression = expresionist.Visit(predicate);
|
||||
sql.Where(whereExpression, expresionist.GetSqlParameters());
|
||||
return sql;
|
||||
var (s, a) = sql.SqlContext.Visit(predicate, alias1, alias2);
|
||||
return sql.Where(s, a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -108,7 +122,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> WhereIn<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, object>> field, IEnumerable values)
|
||||
{
|
||||
var fieldName = GetFieldName(field, sql.SqlContext.SqlSyntax);
|
||||
var fieldName = sql.SqlContext.SqlSyntax.GetFieldName(field);
|
||||
sql.Where(fieldName + " IN (@values)", new { values });
|
||||
return sql;
|
||||
}
|
||||
@@ -136,7 +150,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> WhereNotIn<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, object>> field, IEnumerable values)
|
||||
{
|
||||
var fieldName = GetFieldName(field, sql.SqlContext.SqlSyntax);
|
||||
var fieldName = sql.SqlContext.SqlSyntax.GetFieldName(field);
|
||||
sql.Where(fieldName + " NOT IN (@values)", new { values });
|
||||
return sql;
|
||||
}
|
||||
@@ -164,7 +178,8 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql WhereAnyIn<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, object>>[] fields, IEnumerable values)
|
||||
{
|
||||
var fieldNames = fields.Select(x => GetFieldName(x, sql.SqlContext.SqlSyntax)).ToArray();
|
||||
var sqlSyntax = sql.SqlContext.SqlSyntax;
|
||||
var fieldNames = fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray();
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("(");
|
||||
for (var i = 0; i < fieldNames.Length; i++)
|
||||
@@ -180,7 +195,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
private static Sql<ISqlContext> WhereIn<T>(this Sql<ISqlContext> sql, Expression<Func<T, object>> fieldSelector, Sql valuesSql, bool not)
|
||||
{
|
||||
var fieldName = GetFieldName(fieldSelector, sql.SqlContext.SqlSyntax);
|
||||
var fieldName = sql.SqlContext.SqlSyntax.GetFieldName(fieldSelector);
|
||||
sql.Where(fieldName + (not ? " NOT" : "") +" IN (" + valuesSql.SQL + ")", valuesSql.Arguments);
|
||||
return sql;
|
||||
}
|
||||
@@ -274,7 +289,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> OrderBy<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, object>> field)
|
||||
{
|
||||
return sql.OrderBy("(" + GetFieldName(field, sql.SqlContext.SqlSyntax) + ")");
|
||||
return sql.OrderBy("(" + sql.SqlContext.SqlSyntax.GetFieldName(field) + ")");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -286,9 +301,10 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> OrderBy<TDto>(this Sql<ISqlContext> sql, params Expression<Func<TDto, object>>[] fields)
|
||||
{
|
||||
var sqlSyntax = sql.SqlContext.SqlSyntax;
|
||||
var columns = fields.Length == 0
|
||||
? sql.GetColumns<TDto>(withAlias: false)
|
||||
: fields.Select(x => GetFieldName(x, sql.SqlContext.SqlSyntax)).ToArray();
|
||||
: fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray();
|
||||
return sql.OrderBy(columns);
|
||||
}
|
||||
|
||||
@@ -301,7 +317,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> OrderByDescending<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, object>> field)
|
||||
{
|
||||
return sql.OrderBy("(" + GetFieldName(field, sql.SqlContext.SqlSyntax) + ") DESC");
|
||||
return sql.OrderBy("(" + sql.SqlContext.SqlSyntax.GetFieldName(field) + ") DESC");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -313,9 +329,10 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> OrderByDescending<TDto>(this Sql<ISqlContext> sql, params Expression<Func<TDto, object>>[] fields)
|
||||
{
|
||||
var sqlSyntax = sql.SqlContext.SqlSyntax;
|
||||
var columns = fields.Length == 0
|
||||
? sql.GetColumns<TDto>(withAlias: false)
|
||||
: fields.Select(x => GetFieldName(x, sql.SqlContext.SqlSyntax)).ToArray();
|
||||
: fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray();
|
||||
return sql.OrderBy(columns.Select(x => x + " DESC"));
|
||||
}
|
||||
|
||||
@@ -339,7 +356,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> GroupBy<TDto>(this Sql<ISqlContext> sql, Expression<Func<TDto, object>> field)
|
||||
{
|
||||
return sql.GroupBy(GetFieldName(field, sql.SqlContext.SqlSyntax));
|
||||
return sql.GroupBy(sql.SqlContext.SqlSyntax.GetFieldName(field));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -351,9 +368,10 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> GroupBy<TDto>(this Sql<ISqlContext> sql, params Expression<Func<TDto, object>>[] fields)
|
||||
{
|
||||
var sqlSyntax = sql.SqlContext.SqlSyntax;
|
||||
var columns = fields.Length == 0
|
||||
? sql.GetColumns<TDto>(withAlias: false)
|
||||
: fields.Select(x => GetFieldName(x, sql.SqlContext.SqlSyntax)).ToArray();
|
||||
: fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray();
|
||||
return sql.GroupBy(columns);
|
||||
}
|
||||
|
||||
@@ -366,9 +384,10 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> AndBy<TDto>(this Sql<ISqlContext> sql, params Expression<Func<TDto, object>>[] fields)
|
||||
{
|
||||
var sqlSyntax = sql.SqlContext.SqlSyntax;
|
||||
var columns = fields.Length == 0
|
||||
? sql.GetColumns<TDto>(withAlias: false)
|
||||
: fields.Select(x => GetFieldName(x, sql.SqlContext.SqlSyntax)).ToArray();
|
||||
: fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray();
|
||||
return sql.Append(", " + string.Join(", ", columns));
|
||||
}
|
||||
|
||||
@@ -381,9 +400,10 @@ namespace Umbraco.Core.Persistence
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> AndByDescending<TDto>(this Sql<ISqlContext> sql, params Expression<Func<TDto, object>>[] fields)
|
||||
{
|
||||
var sqlSyntax = sql.SqlContext.SqlSyntax;
|
||||
var columns = fields.Length == 0
|
||||
? sql.GetColumns<TDto>(withAlias: false)
|
||||
: fields.Select(x => GetFieldName(x, sql.SqlContext.SqlSyntax)).ToArray();
|
||||
: fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray();
|
||||
return sql.Append(", " + string.Join(", ", columns.Select(x => x + " DESC")));
|
||||
}
|
||||
|
||||
@@ -572,9 +592,10 @@ namespace Umbraco.Core.Persistence
|
||||
public static Sql<ISqlContext> SelectCount<TDto>(this Sql<ISqlContext> sql, params Expression<Func<TDto, object>>[] fields)
|
||||
{
|
||||
if (sql == null) throw new ArgumentNullException(nameof(sql));
|
||||
var sqlSyntax = sql.SqlContext.SqlSyntax;
|
||||
var columns = fields.Length == 0
|
||||
? sql.GetColumns<TDto>(withAlias: false)
|
||||
: fields.Select(x => GetFieldName(x, sql.SqlContext.SqlSyntax)).ToArray();
|
||||
: fields.Select(x => sqlSyntax.GetFieldName(x)).ToArray();
|
||||
return sql.Select("COUNT (" + string.Join(", ", columns) + ")");
|
||||
}
|
||||
|
||||
@@ -906,7 +927,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
public SqlUpd<TDto> Set(Expression<Func<TDto, object>> fieldSelector, object value)
|
||||
{
|
||||
var fieldName = GetFieldName(fieldSelector, _sqlContext.SqlSyntax);
|
||||
var fieldName = _sqlContext.SqlSyntax.GetFieldName(fieldSelector);
|
||||
_setExpressions.Add(new Tuple<string, object>(fieldName, value));
|
||||
return this;
|
||||
}
|
||||
@@ -1062,17 +1083,6 @@ namespace Umbraco.Core.Persistence
|
||||
return string.IsNullOrWhiteSpace(attr?.Name) ? column.Name : attr.Name;
|
||||
}
|
||||
|
||||
private static string GetFieldName<TDto>(Expression<Func<TDto, object>> fieldSelector, ISqlSyntaxProvider sqlSyntax)
|
||||
{
|
||||
var field = ExpressionHelper.FindProperty(fieldSelector).Item1 as PropertyInfo;
|
||||
var fieldName = field.GetColumnName();
|
||||
|
||||
var type = typeof (TDto);
|
||||
var tableName = type.GetTableName();
|
||||
|
||||
return sqlSyntax.GetQuotedTableName(tableName) + "." + sqlSyntax.GetQuotedColumnName(fieldName);
|
||||
}
|
||||
|
||||
internal static void WriteToConsole(this Sql sql)
|
||||
{
|
||||
Console.WriteLine(sql.SQL);
|
||||
|
||||
78
src/Umbraco.Core/Persistence/SqlContextExtensions.cs
Normal file
78
src/Umbraco.Core/Persistence/SqlContextExtensions.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods to <see cref="ISqlContext"/>.
|
||||
/// </summary>
|
||||
public static class SqlContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Visit an expression.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto">The type of the DTO.</typeparam>
|
||||
/// <param name="sqlContext">An <see cref="ISqlContext"/>.</param>
|
||||
/// <param name="expression">An expression to visit.</param>
|
||||
/// <param name="alias">An optional table alias.</param>
|
||||
/// <returns>A SQL statement, and arguments, corresponding to the expression.</returns>
|
||||
public static (string Sql, object[] Args) Visit<TDto>(this ISqlContext sqlContext, Expression<Func<TDto, object>> expression, string alias = null)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<TDto>(sqlContext, alias);
|
||||
var visited = expresionist.Visit(expression);
|
||||
return (visited, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visit an expression.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto">The type of the DTO.</typeparam>
|
||||
/// <typeparam name="TOut">The type returned by the expression.</typeparam>
|
||||
/// <param name="sqlContext">An <see cref="ISqlContext"/>.</param>
|
||||
/// <param name="expression">An expression to visit.</param>
|
||||
/// <param name="alias">An optional table alias.</param>
|
||||
/// <returns>A SQL statement, and arguments, corresponding to the expression.</returns>
|
||||
public static (string Sql, object[] Args) Visit<TDto, TOut>(this ISqlContext sqlContext, Expression<Func<TDto, TOut>> expression, string alias = null)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<TDto>(sqlContext, alias);
|
||||
var visited = expresionist.Visit(expression);
|
||||
return (visited, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visit an expression.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto1">The type of the first DTO.</typeparam>
|
||||
/// <typeparam name="TDto2">The type of the second DTO.</typeparam>
|
||||
/// <param name="sqlContext">An <see cref="ISqlContext"/>.</param>
|
||||
/// <param name="expression">An expression to visit.</param>
|
||||
/// <param name="alias1">An optional table alias for the first DTO.</param>
|
||||
/// <param name="alias2">An optional table alias for the second DTO.</param>
|
||||
/// <returns>A SQL statement, and arguments, corresponding to the expression.</returns>
|
||||
public static (string Sql, object[] Args) Visit<TDto1, TDto2>(this ISqlContext sqlContext, Expression<Func<TDto1, TDto2, object>> expression, string alias1 = null, string alias2 = null)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<TDto1, TDto2>(sqlContext, alias1, alias2);
|
||||
var visited = expresionist.Visit(expression);
|
||||
return (visited, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visit an expression.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto1">The type of the first DTO.</typeparam>
|
||||
/// <typeparam name="TDto2">The type of the second DTO.</typeparam>
|
||||
/// <typeparam name="TOut">The type returned by the expression.</typeparam>
|
||||
/// <param name="sqlContext">An <see cref="ISqlContext"/>.</param>
|
||||
/// <param name="expression">An expression to visit.</param>
|
||||
/// <param name="alias1">An optional table alias for the first DTO.</param>
|
||||
/// <param name="alias2">An optional table alias for the second DTO.</param>
|
||||
/// <returns>A SQL statement, and arguments, corresponding to the expression.</returns>
|
||||
public static (string Sql, object[] Args) Visit<TDto1, TDto2, TOut>(this ISqlContext sqlContext, Expression<Func<TDto1, TDto2, TOut>> expression, string alias1 = null, string alias2 = null)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<TDto1, TDto2>(sqlContext, alias1, alias2);
|
||||
var visited = expresionist.Visit(expression);
|
||||
return (visited, expresionist.GetSqlParameters());
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/Umbraco.Core/Persistence/SqlSyntaxExtensions.cs
Normal file
48
src/Umbraco.Core/Persistence/SqlSyntaxExtensions.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods to <see cref="ISqlSyntaxProvider"/>.
|
||||
/// </summary>
|
||||
public static class SqlSyntaxExtensions
|
||||
{
|
||||
private static string GetTableName(this Type type)
|
||||
{
|
||||
// todo: returning string.Empty for now
|
||||
// BUT the code bits that calls this method cannot deal with string.Empty so we
|
||||
// should either throw, or fix these code bits...
|
||||
var attr = type.FirstAttribute<TableNameAttribute>();
|
||||
return string.IsNullOrWhiteSpace(attr?.Value) ? string.Empty : attr.Value;
|
||||
}
|
||||
|
||||
private static string GetColumnName(this PropertyInfo column)
|
||||
{
|
||||
var attr = column.FirstAttribute<ColumnAttribute>();
|
||||
return string.IsNullOrWhiteSpace(attr?.Name) ? column.Name : attr.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a quoted table and field name.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto">The type of the DTO.</typeparam>
|
||||
/// <param name="sqlSyntax">An <see cref="ISqlSyntaxProvider"/>.</param>
|
||||
/// <param name="fieldSelector">An expression specifying the field.</param>
|
||||
/// <param name="tableAlias">An optional table alias.</param>
|
||||
/// <returns></returns>
|
||||
public static string GetFieldName<TDto>(this ISqlSyntaxProvider sqlSyntax, Expression<Func<TDto, object>> fieldSelector, string tableAlias = null)
|
||||
{
|
||||
var field = ExpressionHelper.FindProperty(fieldSelector).Item1 as PropertyInfo;
|
||||
var fieldName = field.GetColumnName();
|
||||
|
||||
var type = typeof(TDto);
|
||||
var tableName = tableAlias ?? type.GetTableName();
|
||||
|
||||
return sqlSyntax.GetQuotedTableName(tableName) + "." + sqlSyntax.GetQuotedColumnName(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -406,6 +406,8 @@
|
||||
<Compile Include="Persistence\Repositories\IConsentRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\AuditEntryRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\ConsentRepository.cs" />
|
||||
<Compile Include="Persistence\SqlContextExtensions.cs" />
|
||||
<Compile Include="Persistence\SqlSyntaxExtensions.cs" />
|
||||
<Compile Include="Persistence\UmbracoPocoDataBuilder.cs" />
|
||||
<Compile Include="PropertyEditors\ColorPickerConfiguration.cs" />
|
||||
<Compile Include="PropertyEditors\ConfigurationEditorOfTConfiguration.cs" />
|
||||
|
||||
Reference in New Issue
Block a user