Add typed insert/update/delete builders and typed join variants
This commit is contained in:
17
DynamORM/Builders/DynamicJoinType.cs
Normal file
17
DynamORM/Builders/DynamicJoinType.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Typed join kind used by typed fluent builder APIs.</summary>
|
||||
public enum DynamicJoinType
|
||||
{
|
||||
Inner = 0,
|
||||
Left,
|
||||
Right,
|
||||
Full
|
||||
}
|
||||
}
|
||||
21
DynamORM/Builders/IDynamicTypedDeleteQueryBuilder.cs
Normal file
21
DynamORM/Builders/IDynamicTypedDeleteQueryBuilder.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Typed delete query builder for mapped entities.</summary>
|
||||
/// <typeparam name="T">Mapped entity type.</typeparam>
|
||||
public interface IDynamicTypedDeleteQueryBuilder<T> : IDynamicDeleteQueryBuilder
|
||||
{
|
||||
/// <summary>Add typed where predicate using mapped properties.</summary>
|
||||
/// <param name="predicate">Predicate to parse.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
IDynamicTypedDeleteQueryBuilder<T> Where(Expression<Func<T, bool>> predicate);
|
||||
}
|
||||
}
|
||||
28
DynamORM/Builders/IDynamicTypedInsertQueryBuilder.cs
Normal file
28
DynamORM/Builders/IDynamicTypedInsertQueryBuilder.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Typed insert query builder for mapped entities.</summary>
|
||||
/// <typeparam name="T">Mapped entity type.</typeparam>
|
||||
public interface IDynamicTypedInsertQueryBuilder<T> : IDynamicInsertQueryBuilder
|
||||
{
|
||||
/// <summary>Add typed insert assignment using mapped property selector.</summary>
|
||||
/// <typeparam name="TValue">Property type.</typeparam>
|
||||
/// <param name="selector">Property selector.</param>
|
||||
/// <param name="value">Value to insert.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
IDynamicTypedInsertQueryBuilder<T> Insert<TValue>(Expression<Func<T, TValue>> selector, object value);
|
||||
|
||||
/// <summary>Add values from mapped object.</summary>
|
||||
/// <param name="value">Mapped object value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
IDynamicTypedInsertQueryBuilder<T> Insert(T value);
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,26 @@ namespace DynamORM.Builders
|
||||
/// <typeparam name="T">Mapped entity type.</typeparam>
|
||||
public interface IDynamicTypedSelectQueryBuilder<T> : IDynamicSelectQueryBuilder
|
||||
{
|
||||
/// <summary>Add typed join to mapped table.</summary>
|
||||
/// <typeparam name="TRight">Joined mapped entity type.</typeparam>
|
||||
/// <param name="on">Join ON predicate.</param>
|
||||
/// <param name="alias">Optional alias for joined table.</param>
|
||||
/// <param name="joinType">Join type.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null, DynamicJoinType joinType = DynamicJoinType.Inner);
|
||||
|
||||
/// <summary>Add INNER JOIN using typed ON predicate.</summary>
|
||||
IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
||||
|
||||
/// <summary>Add LEFT JOIN using typed ON predicate.</summary>
|
||||
IDynamicTypedSelectQueryBuilder<T> LeftJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
||||
|
||||
/// <summary>Add RIGHT JOIN using typed ON predicate.</summary>
|
||||
IDynamicTypedSelectQueryBuilder<T> RightJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
||||
|
||||
/// <summary>Add FULL JOIN using typed ON predicate.</summary>
|
||||
IDynamicTypedSelectQueryBuilder<T> FullJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null);
|
||||
|
||||
/// <summary>Add typed where predicate using mapped properties.</summary>
|
||||
/// <param name="predicate">Predicate to parse.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
|
||||
33
DynamORM/Builders/IDynamicTypedUpdateQueryBuilder.cs
Normal file
33
DynamORM/Builders/IDynamicTypedUpdateQueryBuilder.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Typed update query builder for mapped entities.</summary>
|
||||
/// <typeparam name="T">Mapped entity type.</typeparam>
|
||||
public interface IDynamicTypedUpdateQueryBuilder<T> : IDynamicUpdateQueryBuilder
|
||||
{
|
||||
/// <summary>Add typed where predicate using mapped properties.</summary>
|
||||
/// <param name="predicate">Predicate to parse.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
IDynamicTypedUpdateQueryBuilder<T> Where(Expression<Func<T, bool>> predicate);
|
||||
|
||||
/// <summary>Add typed assignment using mapped property selector.</summary>
|
||||
/// <typeparam name="TValue">Property type.</typeparam>
|
||||
/// <param name="selector">Property selector.</param>
|
||||
/// <param name="value">Assigned value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
IDynamicTypedUpdateQueryBuilder<T> Set<TValue>(Expression<Func<T, TValue>> selector, object value);
|
||||
|
||||
/// <summary>Add update values from mapped object.</summary>
|
||||
/// <param name="value">Mapped object value.</param>
|
||||
/// <returns>Builder instance.</returns>
|
||||
IDynamicTypedUpdateQueryBuilder<T> Values(T value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DynamORM.Builders.Implementation
|
||||
{
|
||||
/// <summary>Typed wrapper over <see cref="DynamicDeleteQueryBuilder"/> with property-to-column translation.</summary>
|
||||
/// <typeparam name="T">Mapped entity type.</typeparam>
|
||||
internal class DynamicTypedDeleteQueryBuilder<T> : DynamicDeleteQueryBuilder, IDynamicTypedDeleteQueryBuilder<T>
|
||||
{
|
||||
internal DynamicTypedDeleteQueryBuilder(DynamicDatabase db)
|
||||
: base(db)
|
||||
{
|
||||
}
|
||||
|
||||
public IDynamicTypedDeleteQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
this.WhereTyped(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedDeleteQueryBuilder<T> Where(Func<dynamic, object> func)
|
||||
{
|
||||
base.Where(func);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedDeleteQueryBuilder<T> Where(DynamicColumn column)
|
||||
{
|
||||
base.Where(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedDeleteQueryBuilder<T> Where(string column, DynamicColumn.CompareOperator op, object value)
|
||||
{
|
||||
base.Where(column, op, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedDeleteQueryBuilder<T> Where(string column, object value)
|
||||
{
|
||||
base.Where(column, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedDeleteQueryBuilder<T> Where(object conditions, bool schema = false)
|
||||
{
|
||||
base.Where(conditions, schema);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DynamORM.Builders.Implementation
|
||||
{
|
||||
/// <summary>Typed wrapper over <see cref="DynamicInsertQueryBuilder"/> with property-to-column translation.</summary>
|
||||
/// <typeparam name="T">Mapped entity type.</typeparam>
|
||||
internal class DynamicTypedInsertQueryBuilder<T> : DynamicInsertQueryBuilder, IDynamicTypedInsertQueryBuilder<T>
|
||||
{
|
||||
internal DynamicTypedInsertQueryBuilder(DynamicDatabase db)
|
||||
: base(db)
|
||||
{
|
||||
}
|
||||
|
||||
public IDynamicTypedInsertQueryBuilder<T> Insert<TValue>(Expression<Func<T, TValue>> selector, object value)
|
||||
{
|
||||
this.InsertTyped(selector, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IDynamicTypedInsertQueryBuilder<T> Insert(T value)
|
||||
{
|
||||
base.Insert(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedInsertQueryBuilder<T> Values(Func<dynamic, object> fn, params Func<dynamic, object>[] func)
|
||||
{
|
||||
base.Values(fn, func);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedInsertQueryBuilder<T> Insert(string column, object value)
|
||||
{
|
||||
base.Insert(column, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedInsertQueryBuilder<T> Insert(object o)
|
||||
{
|
||||
base.Insert(o);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,65 @@ namespace DynamORM.Builders.Implementation
|
||||
return this;
|
||||
}
|
||||
|
||||
public IDynamicTypedSelectQueryBuilder<T> Join<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null, DynamicJoinType joinType = DynamicJoinType.Inner)
|
||||
{
|
||||
if (on == null)
|
||||
throw new ArgumentNullException("on");
|
||||
|
||||
DynamicTypeMap rightMapper = DynamicMapperCache.GetMapper(typeof(TRight));
|
||||
if (rightMapper == null)
|
||||
throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", typeof(TRight).FullName));
|
||||
|
||||
string rightTable = rightMapper.Table == null || string.IsNullOrEmpty(rightMapper.Table.Name)
|
||||
? typeof(TRight).Name
|
||||
: rightMapper.Table.Name;
|
||||
string rightOwner = rightMapper.Table == null ? null : rightMapper.Table.Owner;
|
||||
string rightAlias = string.IsNullOrEmpty(alias) ? "t" + (Tables.Count + 1).ToString() : alias;
|
||||
|
||||
BinaryExpression be = on.Body as BinaryExpression;
|
||||
if (be == null || be.NodeType != ExpressionType.Equal)
|
||||
throw new NotSupportedException("Typed join expression is currently limited to equality comparisons.");
|
||||
|
||||
string leftPrefix = GetRootAliasOrTableName();
|
||||
if (string.IsNullOrEmpty(leftPrefix))
|
||||
throw new InvalidOperationException("Join requires source table to be present.");
|
||||
|
||||
string leftExpr = ParseTypedJoinMember<T>(be.Left, leftPrefix, _mapper);
|
||||
string rightExpr = ParseTypedJoinMember<TRight>(be.Right, rightAlias, rightMapper);
|
||||
|
||||
string ownerPrefix = string.IsNullOrEmpty(rightOwner) ? string.Empty : Database.DecorateName(rightOwner) + ".";
|
||||
string rightTableExpr = ownerPrefix + Database.DecorateName(rightTable);
|
||||
string joinExpr = string.Format("{0} {1} AS {2} ON ({3} = {4})",
|
||||
GetJoinKeyword(joinType),
|
||||
rightTableExpr,
|
||||
rightAlias,
|
||||
leftExpr,
|
||||
rightExpr);
|
||||
|
||||
base.Join(x => joinExpr);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IDynamicTypedSelectQueryBuilder<T> InnerJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
||||
{
|
||||
return Join(on, alias, DynamicJoinType.Inner);
|
||||
}
|
||||
|
||||
public IDynamicTypedSelectQueryBuilder<T> LeftJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
||||
{
|
||||
return Join(on, alias, DynamicJoinType.Left);
|
||||
}
|
||||
|
||||
public IDynamicTypedSelectQueryBuilder<T> RightJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
||||
{
|
||||
return Join(on, alias, DynamicJoinType.Right);
|
||||
}
|
||||
|
||||
public IDynamicTypedSelectQueryBuilder<T> FullJoin<TRight>(Expression<Func<T, TRight, bool>> on, string alias = null)
|
||||
{
|
||||
return Join(on, alias, DynamicJoinType.Full);
|
||||
}
|
||||
|
||||
public new IDynamicTypedSelectQueryBuilder<T> Join(params Func<dynamic, object>[] func)
|
||||
{
|
||||
base.Join(func);
|
||||
@@ -454,6 +513,49 @@ namespace DynamORM.Builders.Implementation
|
||||
return parameter != null && parameter.Type == typeof(T);
|
||||
}
|
||||
|
||||
private static string GetJoinKeyword(DynamicJoinType joinType)
|
||||
{
|
||||
switch (joinType)
|
||||
{
|
||||
case DynamicJoinType.Left:
|
||||
return "LEFT JOIN";
|
||||
case DynamicJoinType.Right:
|
||||
return "RIGHT JOIN";
|
||||
case DynamicJoinType.Full:
|
||||
return "FULL JOIN";
|
||||
default:
|
||||
return "INNER JOIN";
|
||||
}
|
||||
}
|
||||
|
||||
private string ParseTypedJoinMember<TModel>(Expression expression, string tablePrefix, DynamicTypeMap mapper)
|
||||
{
|
||||
expression = UnwrapConvert(expression);
|
||||
MemberExpression member = expression as MemberExpression;
|
||||
if (member == null || !(member.Expression is ParameterExpression) || ((ParameterExpression)member.Expression).Type != typeof(TModel))
|
||||
throw new NotSupportedException(string.Format("Typed join member access is not supported: {0}", expression));
|
||||
|
||||
string mappedColumn = null;
|
||||
PropertyInfo property = member.Member as PropertyInfo;
|
||||
if (property != null)
|
||||
{
|
||||
var attrs = property.GetCustomAttributes(typeof(ColumnAttribute), true);
|
||||
ColumnAttribute colAttr = attrs == null ? null : attrs.Cast<ColumnAttribute>().FirstOrDefault();
|
||||
if (colAttr != null && !string.IsNullOrEmpty(colAttr.Name))
|
||||
mappedColumn = colAttr.Name;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(mappedColumn))
|
||||
mappedColumn = mapper.PropertyMap.TryGetValue(member.Member.Name)
|
||||
?? mapper.PropertyMap
|
||||
.Where(x => string.Equals(x.Key, member.Member.Name, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(x => x.Value)
|
||||
.FirstOrDefault()
|
||||
?? member.Member.Name;
|
||||
|
||||
return string.Format("{0}.{1}", tablePrefix, Database.DecorateName(mappedColumn));
|
||||
}
|
||||
|
||||
private static Expression UnwrapConvert(Expression expression)
|
||||
{
|
||||
while (expression is UnaryExpression unary &&
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DynamORM.Builders.Implementation
|
||||
{
|
||||
/// <summary>Typed wrapper over <see cref="DynamicUpdateQueryBuilder"/> with property-to-column translation.</summary>
|
||||
/// <typeparam name="T">Mapped entity type.</typeparam>
|
||||
internal class DynamicTypedUpdateQueryBuilder<T> : DynamicUpdateQueryBuilder, IDynamicTypedUpdateQueryBuilder<T>
|
||||
{
|
||||
internal DynamicTypedUpdateQueryBuilder(DynamicDatabase db)
|
||||
: base(db)
|
||||
{
|
||||
}
|
||||
|
||||
public IDynamicTypedUpdateQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
this.WhereTyped(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IDynamicTypedUpdateQueryBuilder<T> Set<TValue>(Expression<Func<T, TValue>> selector, object value)
|
||||
{
|
||||
this.SetTyped(selector, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IDynamicTypedUpdateQueryBuilder<T> Values(T value)
|
||||
{
|
||||
base.Values(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Update(string column, object value)
|
||||
{
|
||||
base.Update(column, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Update(object conditions)
|
||||
{
|
||||
base.Update(conditions);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Set(params Func<dynamic, object>[] func)
|
||||
{
|
||||
base.Set(func);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Values(string column, object value)
|
||||
{
|
||||
base.Values(column, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Values(object o)
|
||||
{
|
||||
base.Values(o);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Where(Func<dynamic, object> func)
|
||||
{
|
||||
base.Where(func);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Where(DynamicColumn column)
|
||||
{
|
||||
base.Where(column);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Where(string column, DynamicColumn.CompareOperator op, object value)
|
||||
{
|
||||
base.Where(column, op, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Where(string column, object value)
|
||||
{
|
||||
base.Where(column, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public new IDynamicTypedUpdateQueryBuilder<T> Where(object conditions, bool schema = false)
|
||||
{
|
||||
base.Where(conditions, schema);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,16 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using DynamORM.Helpers;
|
||||
using DynamORM.Mapper;
|
||||
|
||||
namespace DynamORM.Builders
|
||||
{
|
||||
/// <summary>Typed join helpers for typed select builder.</summary>
|
||||
/// <summary>Compatibility and convenience extensions for typed joins.</summary>
|
||||
public static class TypedJoinExtensions
|
||||
{
|
||||
/// <summary>Add typed join on mapped members. Supports simple equality join expression only.</summary>
|
||||
/// <summary>
|
||||
/// Legacy compatibility helper. Prefer <see cref="IDynamicTypedSelectQueryBuilder{T}.Join{TRight}"/>.
|
||||
/// </summary>
|
||||
public static IDynamicTypedSelectQueryBuilder<TLeft> JoinTyped<TLeft, TRight>(
|
||||
this IDynamicTypedSelectQueryBuilder<TLeft> builder,
|
||||
string alias,
|
||||
@@ -25,62 +24,53 @@ namespace DynamORM.Builders
|
||||
if (builder == null) throw new ArgumentNullException("builder");
|
||||
if (on == null) throw new ArgumentNullException("on");
|
||||
|
||||
var rightMapper = DynamicMapperCache.GetMapper(typeof(TRight));
|
||||
if (rightMapper == null)
|
||||
throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", typeof(TRight).FullName));
|
||||
DynamicJoinType jt = DynamicJoinType.Inner;
|
||||
string normalized = (joinType ?? string.Empty).Trim().ToUpperInvariant();
|
||||
|
||||
string rightTable = string.IsNullOrEmpty(rightMapper.Table.NullOr(t => t.Name))
|
||||
? typeof(TRight).Name
|
||||
: rightMapper.Table.Name;
|
||||
if (normalized == "LEFT JOIN" || normalized == "LEFT")
|
||||
jt = DynamicJoinType.Left;
|
||||
else if (normalized == "RIGHT JOIN" || normalized == "RIGHT")
|
||||
jt = DynamicJoinType.Right;
|
||||
else if (normalized == "FULL JOIN" || normalized == "FULL")
|
||||
jt = DynamicJoinType.Full;
|
||||
|
||||
string rightOwner = rightMapper.Table.NullOr(t => t.Owner);
|
||||
string rightAlias = string.IsNullOrEmpty(alias) ? "t" + (builder.Tables.Count + 1).ToString() : alias;
|
||||
|
||||
var be = on.Body as BinaryExpression;
|
||||
if (be == null || be.NodeType != ExpressionType.Equal)
|
||||
throw new NotSupportedException("JoinTyped currently supports only equality join expressions.");
|
||||
|
||||
string leftPrefix = builder.Tables.FirstOrDefault().NullOr(t => string.IsNullOrEmpty(t.Alias) ? t.Name : t.Alias, null);
|
||||
if (string.IsNullOrEmpty(leftPrefix))
|
||||
throw new InvalidOperationException("JoinTyped requires source table to be present.");
|
||||
|
||||
string leftExpr = ResolveMappedSide(be.Left, typeof(TLeft), leftPrefix, builder.Database);
|
||||
string rightExpr = ResolveMappedSide(be.Right, typeof(TRight), rightAlias, builder.Database);
|
||||
|
||||
string ownerPrefix = string.IsNullOrEmpty(rightOwner) ? string.Empty : builder.Database.DecorateName(rightOwner) + ".";
|
||||
string rightTableExpr = ownerPrefix + builder.Database.DecorateName(rightTable);
|
||||
string joinExpr = string.Format("{0} {1} AS {2} ON ({3} = {4})", joinType, rightTableExpr, rightAlias, leftExpr, rightExpr);
|
||||
|
||||
builder.Join(x => joinExpr);
|
||||
return builder;
|
||||
return builder.Join(on, alias, jt);
|
||||
}
|
||||
|
||||
private static string ResolveMappedSide(Expression expression, Type modelType, string prefix, DynamicDatabase db)
|
||||
/// <summary>Convenience typed INNER JOIN extension.</summary>
|
||||
public static IDynamicTypedSelectQueryBuilder<TLeft> InnerJoinTyped<TLeft, TRight>(
|
||||
this IDynamicTypedSelectQueryBuilder<TLeft> builder,
|
||||
Expression<Func<TLeft, TRight, bool>> on,
|
||||
string alias = null)
|
||||
{
|
||||
expression = UnwrapConvert(expression);
|
||||
var member = expression as MemberExpression;
|
||||
if (member == null)
|
||||
throw new NotSupportedException("Join side must be mapped member access.");
|
||||
|
||||
var mapper = DynamicMapperCache.GetMapper(modelType);
|
||||
string col = mapper.PropertyMap.TryGetValue(member.Member.Name)
|
||||
?? mapper.PropertyMap
|
||||
.Where(x => string.Equals(x.Key, member.Member.Name, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(x => x.Value)
|
||||
.FirstOrDefault()
|
||||
?? member.Member.Name;
|
||||
|
||||
return string.Format("{0}.{1}", prefix, db.DecorateName(col));
|
||||
return builder.Join(on, alias, DynamicJoinType.Inner);
|
||||
}
|
||||
|
||||
private static Expression UnwrapConvert(Expression expression)
|
||||
/// <summary>Convenience typed LEFT JOIN extension.</summary>
|
||||
public static IDynamicTypedSelectQueryBuilder<TLeft> LeftJoinTyped<TLeft, TRight>(
|
||||
this IDynamicTypedSelectQueryBuilder<TLeft> builder,
|
||||
Expression<Func<TLeft, TRight, bool>> on,
|
||||
string alias = null)
|
||||
{
|
||||
while (expression is UnaryExpression &&
|
||||
(((UnaryExpression)expression).NodeType == ExpressionType.Convert ||
|
||||
((UnaryExpression)expression).NodeType == ExpressionType.ConvertChecked))
|
||||
expression = ((UnaryExpression)expression).Operand;
|
||||
return builder.Join(on, alias, DynamicJoinType.Left);
|
||||
}
|
||||
|
||||
return expression;
|
||||
/// <summary>Convenience typed RIGHT JOIN extension.</summary>
|
||||
public static IDynamicTypedSelectQueryBuilder<TLeft> RightJoinTyped<TLeft, TRight>(
|
||||
this IDynamicTypedSelectQueryBuilder<TLeft> builder,
|
||||
Expression<Func<TLeft, TRight, bool>> on,
|
||||
string alias = null)
|
||||
{
|
||||
return builder.Join(on, alias, DynamicJoinType.Right);
|
||||
}
|
||||
|
||||
/// <summary>Convenience typed FULL JOIN extension.</summary>
|
||||
public static IDynamicTypedSelectQueryBuilder<TLeft> FullJoinTyped<TLeft, TRight>(
|
||||
this IDynamicTypedSelectQueryBuilder<TLeft> builder,
|
||||
Expression<Func<TLeft, TRight, bool>> on,
|
||||
string alias = null)
|
||||
{
|
||||
return builder.Join(on, alias, DynamicJoinType.Full);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,10 +503,12 @@ namespace DynamORM
|
||||
/// <summary>Adds to the <code>INSERT INTO</code> clause using <see cref="Type"/>.</summary>
|
||||
/// <typeparam name="T">Type which can be represented in database.</typeparam>
|
||||
/// <returns>This instance to permit chaining.</returns>
|
||||
public virtual IDynamicInsertQueryBuilder Insert<T>()
|
||||
{
|
||||
return new DynamicInsertQueryBuilder(this).Table(typeof(T));
|
||||
}
|
||||
public virtual IDynamicTypedInsertQueryBuilder<T> Insert<T>()
|
||||
{
|
||||
DynamicTypedInsertQueryBuilder<T> builder = new DynamicTypedInsertQueryBuilder<T>(this);
|
||||
builder.Table(typeof(T));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>Adds to the <code>INSERT INTO</code> clause using <see cref="Type"/>.</summary>
|
||||
/// <param name="t">Type which can be represented in database.</param>
|
||||
@@ -610,10 +612,12 @@ namespace DynamORM
|
||||
/// <summary>Adds to the <code>UPDATE</code> clause using <see cref="Type"/>.</summary>
|
||||
/// <typeparam name="T">Type which can be represented in database.</typeparam>
|
||||
/// <returns>This instance to permit chaining.</returns>
|
||||
public virtual IDynamicUpdateQueryBuilder Update<T>()
|
||||
{
|
||||
return new DynamicUpdateQueryBuilder(this).Table(typeof(T));
|
||||
}
|
||||
public virtual IDynamicTypedUpdateQueryBuilder<T> Update<T>()
|
||||
{
|
||||
DynamicTypedUpdateQueryBuilder<T> builder = new DynamicTypedUpdateQueryBuilder<T>(this);
|
||||
builder.Table(typeof(T));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>Adds to the <code>UPDATE</code> clause using <see cref="Type"/>.</summary>
|
||||
/// <param name="t">Type which can be represented in database.</param>
|
||||
@@ -831,10 +835,12 @@ namespace DynamORM
|
||||
/// <summary>Adds to the <code>DELETE FROM</code> clause using <see cref="Type"/>.</summary>
|
||||
/// <typeparam name="T">Type which can be represented in database.</typeparam>
|
||||
/// <returns>This instance to permit chaining.</returns>
|
||||
public virtual IDynamicDeleteQueryBuilder Delete<T>()
|
||||
{
|
||||
return new DynamicDeleteQueryBuilder(this).Table(typeof(T));
|
||||
}
|
||||
public virtual IDynamicTypedDeleteQueryBuilder<T> Delete<T>()
|
||||
{
|
||||
DynamicTypedDeleteQueryBuilder<T> builder = new DynamicTypedDeleteQueryBuilder<T>(this);
|
||||
builder.Table(typeof(T));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>Adds to the <code>DELETE FROM</code> clause using <see cref="Type"/>.</summary>
|
||||
/// <param name="t">Type which can be represented in database.</param>
|
||||
|
||||
Reference in New Issue
Block a user