/*
Kooboo is a content management system based on ASP.NET MVC framework. Copyright 2009 Yardi Technology Limited.
This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program.
If not, see http://www.kooboo.com/gpl3/.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Everest.Library.Data.Entity{
public static class EfUtility
{
/// <summary>
/// Composes the specified first.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first">The first.</param>
/// <param name="second">The second.</param>
/// <param name="merge">The merge.</param>
/// <returns></returns>
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
/// <summary>
/// And the specified first.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first">The first.</param>
/// <param name="second">The second.</param>
/// <returns></returns>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
/// <summary>
/// Or the specified first.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first">The first.</param>
/// <param name="second">The second.</param>
/// <returns></returns>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
/// <summary>
/// Builds the contains expression.
/// The Entity Framework does not currently support collection-valued parameters.
/// </summary>
/// <typeparam name="TElement">The type of the element.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="valueSelector">The value selector.</param>
/// <param name="values">The values.</param>
/// <returns></returns>
public static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
{
if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); }
if (null == values) { throw new ArgumentNullException("values"); }
ParameterExpression p = valueSelector.Parameters.Single();
// p => valueSelector(p) == values[0] || valueSelector(p) == ...
if (!values.Any())
{
return e => false;
}
var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
/// <summary>
/// Builds the not in expression.
/// </summary>
/// <typeparam name="TElement">The type of the element.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="valueSelector">The value selector.</param>
/// <param name="values">The values.</param>
/// <returns></returns>
public static Expression<Func<TElement, bool>> BuildNotInExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
{
if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); }
if (null == values) { throw new ArgumentNullException("values"); }
ParameterExpression p = valueSelector.Parameters.Single();
// p => valueSelector(p) == values[0] || valueSelector(p) == ...
if (!values.Any())
{
return e => false;
}
var notEquals = values.Select(value => (Expression)Expression.NotEqual(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
var body = notEquals.Aggregate<Expression>((accumulate, equal) => Expression.And(accumulate, equal));
return Expression.Lambda<Func<TElement, bool>>(body, p);
}
}
}
|