Extend NPoco fluent querying
This commit is contained in:
@@ -392,6 +392,23 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
#region Joins
|
||||
|
||||
/// <summary>
|
||||
/// Appends a CROSS JOIN clause to the Sql statement.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto">The type of the Dto.</typeparam>
|
||||
/// <param name="sql">The Sql statement.</param>
|
||||
/// <param name="alias">An optional alias for the joined table.</param>
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> CrossJoin<TDto>(this Sql<ISqlContext> sql, string alias = null)
|
||||
{
|
||||
var type = typeof(TDto);
|
||||
var tableName = type.GetTableName();
|
||||
var join = sql.SqlContext.SqlSyntax.GetQuotedTableName(tableName);
|
||||
if (alias != null) join += " " + sql.SqlContext.SqlSyntax.GetQuotedTableName(alias);
|
||||
|
||||
return sql.Append("CROSS JOIN " + join);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends an INNER JOIN clause to the Sql statement.
|
||||
/// </summary>
|
||||
@@ -533,6 +550,25 @@ namespace Umbraco.Core.Persistence
|
||||
return sqlJoin.On(onExpression, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends an ON clause to a SqlJoin statement.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto1">The type of Dto 1.</typeparam>
|
||||
/// <typeparam name="TDto2">The type of Dto 2.</typeparam>
|
||||
/// <typeparam name="TDto3">The type of Dto 3.</typeparam>
|
||||
/// <param name="sqlJoin">The SqlJoin statement.</param>
|
||||
/// <param name="predicate">A predicate to transform and use as the ON clause body.</param>
|
||||
/// <param name="aliasLeft">An optional alias for Dto 1 table.</param>
|
||||
/// <param name="aliasRight">An optional alias for Dto 2 table.</param>
|
||||
/// <param name="aliasOther">An optional alias for Dto 3 table.</param>
|
||||
/// <returns>The Sql statement.</returns>
|
||||
public static Sql<ISqlContext> On<TDto1, TDto2, TDto3>(this Sql<ISqlContext>.SqlJoinClause<ISqlContext> sqlJoin, Expression<Func<TDto1, TDto2, TDto3, bool>> predicate, string aliasLeft = null, string aliasRight = null, string aliasOther = null)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionVisitor<TDto1, TDto2, TDto3>(sqlJoin.SqlContext, aliasLeft, aliasRight, aliasOther);
|
||||
var onExpression = expresionist.Visit(predicate);
|
||||
return sqlJoin.On(onExpression, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Select
|
||||
|
||||
@@ -167,4 +167,93 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an expression tree parser used to turn strongly typed expressions into SQL statements.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto1">The type of DTO 1.</typeparam>
|
||||
/// <typeparam name="TDto2">The type of DTO 2.</typeparam>
|
||||
/// <typeparam name="TDto3">The type of DTO 3.</typeparam>
|
||||
/// <remarks>This visitor is stateful and cannot be reused.</remarks>
|
||||
internal class PocoToSqlExpressionVisitor<TDto1, TDto2, TDto3> : ExpressionVisitorBase
|
||||
{
|
||||
private readonly PocoData _pocoData1, _pocoData2, _pocoData3;
|
||||
private readonly string _alias1, _alias2, _alias3;
|
||||
private string _parameterName1, _parameterName2, _parameterName3;
|
||||
|
||||
public PocoToSqlExpressionVisitor(ISqlContext sqlContext, string alias1, string alias2, string alias3)
|
||||
: base(sqlContext.SqlSyntax)
|
||||
{
|
||||
_pocoData1 = sqlContext.PocoDataFactory.ForType(typeof(TDto1));
|
||||
_pocoData2 = sqlContext.PocoDataFactory.ForType(typeof(TDto2));
|
||||
_pocoData3 = sqlContext.PocoDataFactory.ForType(typeof(TDto3));
|
||||
_alias1 = alias1;
|
||||
_alias2 = alias2;
|
||||
_alias3 = alias3;
|
||||
}
|
||||
|
||||
protected override string VisitLambda(LambdaExpression lambda)
|
||||
{
|
||||
if (lambda.Parameters.Count == 3)
|
||||
{
|
||||
_parameterName1 = lambda.Parameters[0].Name;
|
||||
_parameterName2 = lambda.Parameters[1].Name;
|
||||
_parameterName3 = lambda.Parameters[2].Name;
|
||||
}
|
||||
else if (lambda.Parameters.Count == 2)
|
||||
{
|
||||
_parameterName1 = lambda.Parameters[0].Name;
|
||||
_parameterName2 = lambda.Parameters[1].Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
_parameterName1 = _parameterName2 = null;
|
||||
}
|
||||
return base.VisitLambda(lambda);
|
||||
}
|
||||
|
||||
protected override string VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
if (m.Expression != null)
|
||||
{
|
||||
if (m.Expression.NodeType == ExpressionType.Parameter)
|
||||
{
|
||||
var pex = (ParameterExpression)m.Expression;
|
||||
|
||||
if (pex.Name == _parameterName1)
|
||||
return Visited ? string.Empty : GetFieldName(_pocoData1, m.Member.Name, _alias1);
|
||||
|
||||
if (pex.Name == _parameterName2)
|
||||
return Visited ? string.Empty : GetFieldName(_pocoData2, m.Member.Name, _alias2);
|
||||
|
||||
if (pex.Name == _parameterName3)
|
||||
return Visited ? string.Empty : GetFieldName(_pocoData3, m.Member.Name, _alias3);
|
||||
}
|
||||
else if (m.Expression.NodeType == ExpressionType.Convert)
|
||||
{
|
||||
// here: which _pd should we use?!
|
||||
throw new NotSupportedException();
|
||||
//return Visited ? string.Empty : GetFieldName(_pd, m.Member.Name);
|
||||
}
|
||||
}
|
||||
|
||||
var member = Expression.Convert(m, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
var o = getter();
|
||||
|
||||
SqlParameters.Add(o);
|
||||
|
||||
// execute if not already compiled
|
||||
return Visited ? string.Empty : "@" + (SqlParameters.Count - 1);
|
||||
}
|
||||
|
||||
protected virtual string GetFieldName(PocoData pocoData, string name, string alias)
|
||||
{
|
||||
var column = pocoData.Columns.FirstOrDefault(x => x.Value.MemberInfoData.Name == name);
|
||||
var tableName = SqlSyntax.GetQuotedTableName(alias ?? pocoData.TableInfo.TableName);
|
||||
var columnName = SqlSyntax.GetQuotedColumnName(column.Value.ColumnName);
|
||||
|
||||
return tableName + "." + columnName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user