// List ctor public List<T>(IEnumerable<T> source) { // IEnumerator WhereListIterator. var enumerator = source.GetEnumerator(); // WhereListIterator' while(enumerator.MoveNext()) { items.Add(enumerator.Current) } }
public List<T>(IQueryable<T> source) { // IEnumerator WhereListIterator. var enumerator = source.GetEnumerator(); // WhereListIterator' while(enumerator.MoveNext()) { items.Add(enumerator.Current) } } public class EnumerableQueryable<T> : IQueryable<T> { private Expression expression; private IEnumerable enumerableResult; public IEnumerator GetEnumerator() { if (enumerableResult == null) enumerableResult = expression.Compile().Invoke(); return enumerableResult.GetEnumerator(); } }
var activeMasterEntities = session // NhQueryable<T>, ConstantExpression , . .Query<Entity>() // IQueryable, MethodCallExpression , ConstantExpression. .Where(e => e.IsMaster == true) // IQueryable, MethodCallExpression , MethodCallExpression. .Where(e => e.IsActive == true) // .ToList()
int stateCoefficient = 0.9; int ageLimitInCurrentState = 18 * stateCoefficient; var availableMovies = session .Query<Movie>() .Where(m => m.AgeLimit >= ageLimitInCurrentState) .ToList()
public class NhQueryable<T> : QueryableBase<T> { public NhQueryable(ISessionImplementor session) { // INhQueryProvider Provider = QueryProviderFactory.CreateQueryProvider(session); // . Expression = Expression.Constant(this); } }
public class RemoteQueryable<T> : IQueryable<T> { public Expression Expression { get; set; } public Type ElementType { get; set; } public IQueryProvider Provider { get; set; } public RemoteQueryable() { Expression = Expression.Constant(this); } }
var query = new RemoteQueryable<Entity>().Where(e => e.IsMaster);
public static class RemoteRepository { public static IQueryable<TResult> CreateQuery<TResult>(IChannelProvider provider) { return new RemoteQueryable<TResult>(provider); } }
var query = RemoteRepository.CreateQuery<Entity>() .Where(e => e.IsMaster) .Where(e => e.IsActive);
public class NhibernateExpressionVisitor : ExpressionVisitor { protected IQueryable queryableRoot; public new Expression Visit(Expression sourceExpression, IQueryable queryableRoot) { this.queryableRoot= queryableRoot; return Visit(sourceExpression); } protected override Expression VisitMethodCall(MethodCallExpression m) { var query = m; var constantArgument = query.Arguments.FirstOrDefault(e => e is ConstantExpression && e.Type.IsGenericType && e.Type.GetGenericTypeDefinition() == typeof(EnumerableQuery<>)); if (constantArgument != null) { var constantArgumentPosition = query.Arguments.IndexOf(constantArgument); var newArguments = new Expression[query.Arguments.Count]; for (int index = 0; index < newArguments.Length; index++) { if (index != constantArgumentPosition) newArguments[index] = query.Arguments[index]; else newArguments[index] = queryableRoot.Expression; } return Expression.Call(query.Object, query.Method, newArguments); } return base.VisitMethodCall(query); } protected override Expression VisitConstant(ConstantExpression c) { if (c.Type.IsGenericType && typeof(RemoteQueryable<>).IsAssignableFrom(c.Type.GetGenericTypeDefinition())) return queryableRoot.Expression; return c; } }
var query = RemoteRepository.CreateQuery<Entity>() .Where(e => e.IsMaster) .Where(e => e.IsActive); using (var session = CreateSession()) { var nhQueryable = session.Query<Entity>(); var nhQueryableWithExternalQuery = new NhibernateExpressionVisitor().Visit(query.Expression, nhQueryable); var result = nhQueryable.Provider.Execute(nhQueryableWithExternalQuery); }
public interface IChannelProvider { T SendRequest<T>(string request); }
public RemoteQueryable(IChannelProvider channelProvider) { Expression = Expression.Constant(this); Provider = new RemoteQueryableProvider<T>(channelProvider); } public static IQueryable<TResult> CreateQuery<TResult>(IChannelProvider provider) { return new RemoteQueryable<TResult>(provider); }
public class RemoteQueryProvider : IQueryProvider { public IQueryable CreateQuery(Expression expression) { var enumerableQuery = new EnumerableQuery<T>(expression); var resultQueryable = ((IQueryProvider)enumerableQuery).CreateQuery(expression); return new RemoteQueryable<T>(this, resultQueryable.Expression); } public IQueryable<TElement> CreateQuery<TElement>(Expression expression) { var enumerableQuery = new EnumerableQuery<TElement>(expression); var resultQueryable = ((IQueryProvider)enumerableQuery).CreateQuery<TElement>(expression); return new RemoteQueryable<TElement>(this, resultQueryable.Expression); } public object Execute(Expression expression) { var serializedQuery = SerializeQuery(expression); return channelProvider.SendRequest<object>(serializedQuery); } public TResult Execute<TResult>(Expression expression) { var serializedQuery = SerializeQuery(expression); return this.channelProvider.SendRequest<TResult>(serializedQuery); } public RemoteQueryableProvider(IChannelProvider channelProvider) { this.channelProvider = channelProvider; } private static string SerializeQuery(Expression expression) { var newQueryDto = QueryDto.CreateMessage(expression, typeof(T)); var serializedQuery = JsonConvert.SerializeObject(newQueryDto, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, TypeNameHandling = TypeNameHandling.All }); return serializedQuery; } }
public class QueryDto { public ExpressionNode SerializedExpression { get; set; } public string RequestedTypeName { get; set; } public string RequestedTypeAssemblyName { get; set; } public static QueryDtoCreateMessage(Expression expression, Type type) { var serializedExpression = expression.ToExpressionNode(); return new QueryDto(serializedExpression, type.FullName, type.Assembly.FullName); } private QueryDto(ExpressionNode serializedExpression, string requestedTypeName, string requestedTypeAssemblyName) { this.SerializedExpression = serializedExpression; this.RequestedTypeName = requestedTypeName; this.RequestedTypeAssemblyName = requestedTypeAssemblyName; } protected QueryDto() { } }
RemoteRepository.Query<WorkItem>() .Where(w => w.Priority == EnvironmentSettings.MaxPriority)) // EnvironmentSettings
internal class ClientExpressionVisitor : ExpressionVisitor { public Expression Evaluate(Expression expression) { return base.Visit(expression); } private Expression EvaluateIfNeed(Expression expression) { var memberExpression = expression as MemberExpression; if (memberExpression != null) { if (memberExpression.Expression is ParameterExpression) return expression; var rightValue = GetValue(memberExpression); return Expression.Constant(rightValue); } var methodCallExpression = expression as MethodCallExpression; if (methodCallExpression != null) { var obj = ((ConstantExpression)methodCallExpression.Object).Value; var result = methodCallExpression.Method.Invoke(obj, methodCallExpression.Arguments.Select(ResolveArgument).ToArray()); return Expression.Constant(result); } return expression; } protected override Expression VisitBinary(BinaryExpression b) { Expression left = this.EvaluateIfNeed(this.Visit(b.Left)); Expression right = this.EvaluateIfNeed(this.Visit(b.Right)); Expression conversion = this.Visit(b.Conversion); if (left != b.Left || right != b.Right || conversion != b.Conversion) { if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) return Expression.Coalesce(left, right, conversion as LambdaExpression); else return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); } return b; } private static object ResolveArgument(Expression exp) { var constantExp = exp as ConstantExpression; if (constantExp != null) return constantExp.Value; var memberExp = exp as MemberExpression; if (memberExp != null) return GetValue(memberExp); return null; } private static object GetValue(MemberExpression exp) { var constantExpression = exp.Expression as ConstantExpression; if (constantExpression != null) { var member = constantExpression.Value .GetType() .GetMember(exp.Member.Name) .First(); var fieldInfo = member as FieldInfo; if (fieldInfo != null) return fieldInfo.GetValue(constantExpression.Value); var propertyInfo = member as PropertyInfo; if (propertyInfo != null) return propertyInfo.GetValue(constantExpression.Value); } var expression = exp.Expression as MemberExpression; if (expression != null) return GetValue(expression); return null; } }
public object Execute(Expression expression) { var partialEvaluatedExpression = this.expressionEvaluator.Evaluate(expression); var serializedQuery = SerializeQuery(partialEvaluatedExpression); return channelProvider.SendRequest<object>(serializedQuery); } public TResult Execute<TResult>(Expression expression) { var partialEvaluatedExpression = this.expressionEvaluator.Evaluate(expression); var serializedQuery = SerializeQuery(partialEvaluatedExpression); return this.channelProvider.SendRequest<TResult>(serializedQuery); }
internal class PostQueryable<T> : BaseQueryable<T> { public PostQueryable(IChannelProvider channelProvider) : base(channelProvider) { } public PostQueryable(AbstractQueryProvider provider, Expression expression) : base(provider, expression) { } public PostQueryable() { Expression = Expression.Constant(this); } }
public static class Ex { public static IQueryable<T> PostQuery<T>(this IQueryable<T> sourceQuery) { var query = Expression .Call(null, typeof (PostQueryable<T>).GetMethod(nameof(PostQueryable<T>.WrapQuery)), new [] {sourceQuery.Expression}); return sourceQuery.Provider.CreateQuery<T>(query); } }
int stateCoefficient = 0.9; int ageLimitInCurrentState = 18 * stateCoefficient; var availableMovies = session .Query<Movie>() .Where(m => m.AgeLimit >= ageLimitInCurrentState) .PostQuery() .Where(m => m.RatingInCurrentState > 8) // unmapped- RatingInCurrentState .ToList()
internal static class NHibernateTypesHelper { private static readonly Assembly nhibernateAssembly; public static Type SessionType { get; private set; } public static Type LinqExtensionType { get; private set; } public static bool IsSessionObject(object inspectedObject) { return SessionType.IsInstanceOfType(inspectedObject); } static NHibernateTypesHelper() { nhibernateAssembly = AppDomain.CurrentDomain.GetAssemblies() .FirstOrDefault(asm => asm.FullName.Contains("NHibernate")) ?? Assembly.Load("NHibernate"); if (nhibernateAssembly == null) throw new InvalidOperationException("Caller invoking server-side types, but the NHibernate.dll not found in current application domain"); SessionType = nhibernateAssembly.GetTypes() .Single(p => p.FullName.Equals("NHibernate.ISession", StringComparison.OrdinalIgnoreCase)); LinqExtensionType = nhibernateAssembly.GetTypes() Single(p => p.FullName.Equals("NHibernate.Linq.LinqExtensionMethods", StringComparison.OrdinalIgnoreCase)); } }
public static class RemoteQueryExecutor { public static object Do(string serializedQueryDto, object sessionObject) { var internalRemoteQuery = DeserializeQueryDto(serializedQueryDto); var deserializedQuery = DeserializedQueryExpressionAndValidate(internalRemoteQuery); var targetType = ResolveType(internalRemoteQuery); return Execute(deserializedQuery, targetType, sessionObject); } private static TypeInfo ResolveType(QueryDto internalRemoteQuery) { var targetAssemblyName = internalRemoteQuery.RequestedTypeAssemblyName; var targetAssembly = GetAssemblyOrThrownEx(internalRemoteQuery, targetAssemblyName); var targetType = GetTypeFromAssemblyOrThrownEx(targetAssembly, internalRemoteQuery.RequestedTypeName, targetAssemblyName); return targetType; } private static Expression DeserializedQueryExpression(QueryDto internalRemoteQuery) { var deserializedQuery = internalRemoteQuery.SerializedExpression.ToExpression(); return deserializedQuery; } private static TypeInfo GetTypeFromAssemblyOrThrownEx(Assembly targetAssembly, string requestedTypeName, string targetAssemblyName) { var targetType = targetAssembly.DefinedTypes .FirstOrDefault(type => type.FullName.Equals(requestedTypeName, StringComparison.OrdinalIgnoreCase)); if (targetType == null) throw new InvalidOperationException(string.Format("Type with name '{0}' not found in assembly '{1}'", requestedTypeName, targetAssemblyName)); return targetType; } private static Assembly GetAssemblyOrThrownEx(QueryDto internalRemoteQuery, string targetAssemblyName) { var targetAssembly = AppDomain.CurrentDomain.GetAssemblies() .FirstOrDefault(asm => asm.FullName.Equals(internalRemoteQuery.RequestedTypeAssemblyName, StringComparison.OrdinalIgnoreCase)); if (targetAssembly == null) throw new InvalidOperationException(string.Format("Assembly with name '{0}' not found in server app domain", targetAssemblyName)); return targetAssembly; } private static QueryDto DeserializeQueryDto(string serializedQueryDto) { var internalRemoteQuery = JsonConvert .DeserializeObject<QueryDto>(serializedQueryDto, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, TypeNameHandling = TypeNameHandling.All }); return internalRemoteQuery; } private static object Execute(Expression expression, Type targetType, object sessionObject) { var queryable = GetNhQueryableFromSession(targetType, sessionObject); var nhibernatePartialExpression = ExpressionModifier.GetNhibernatePartialExpression(expression, queryable); var resultFromStorage = queryable.Provider.Execute(nhibernatePartialExpression); var requestedCollection = resultFromStorage as IEnumerable<object>; if (requestedCollection == null) return resultFromStorage; var resultCollectionType = requestedCollection.GetType(); if (resultCollectionType.IsGenericType) targetType = resultCollectionType.GetGenericArguments().Single(); var enumerableQueryable = (IQueryable)Activator .CreateInstance(typeof(EnumerableQuery<>).MakeGenericType(targetType), new[] { requestedCollection }); var postQueryPartialExpression = ExpressionModifier .GetPostQueryPartialExpression(expression, enumerableQueryable); if (postQueryPartialExpression == null) return resultFromStorage; return enumerableQueryable.Provider.Execute(postQueryPartialExpression); } private static IQueryable GetNhQueryableFromSession(Type targetType, object sessionObject) { var finalQueryMethod = ResolveQueryMethod(targetType); var queryable = (IQueryable) finalQueryMethod.Invoke(null, new object[] {sessionObject}); return queryable; } private static MethodInfo ResolveQueryMethod(Type targetType) { var queryMethod = typeof(LinqExtensionMethods).GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(m => m.IsGenericMethod) .Where(m => m.Name.Equals("Query")) .Single(m => m.GetParameters().Length == 1 && NHibernateTypesHelper.SessionType.IsAssignableFrom(m.GetParameters().First().ParameterType)); var finalQueryMethod = queryMethod.MakeGenericMethod(targetType); return finalQueryMethod; } }
[DataContract] public class WorkItem : BaseEntity { [DataMember] public virtual string Text { get; set; } [DataMember] public virtual int Priority { get; set; } }
public class DemoWorkItemProvider : IItemsProvider<WorkItem> { public int FetchCount() { return RemoteRepository.CreateQuery<WorkItem>(new DemoChannelProvider()) .Count(); } public IList<WorkItem> FetchRange(int startIndex, int count) { return RemoteRepository.CreateQuery<WorkItem>(new DemoChannelProvider()) .Skip(startIndex) .Take(count) .ToList(); } }
Source: https://habr.com/ru/post/302594/
All Articles