简体   繁体   中英

Linq-SQL Generic GetById with a custom Expression

I've created a generic to target tables in my database. I've also added a generic .where() with an expression containing only 1 parameter in the lambda expression. Is there a way that I can add more than 1 parameter in the same expression? Please ignore the fact that the below method returns 1 item, I would like to make it return a IList.

Here's my method:

public virtual T GetById( Int32 id, String someStringColumn )
{
   ParameterExpression itemParameter = Expression.Parameter( typeof( T ), "item" );
   var whereExpression = Expression.Lambda<Func<T, Boolean>>
                (
                Expression.Equal( Expression.Property( itemParameter, "Id" ), Expression.Constant( id ) ),
                new[] { itemParameter }
                );

   return context.Set<T>().Where( whereExpression ).FirstOrDefault();
   }

My actual intentions for this method is to later perform a Contains() on "string" properties of the target table "T". I would like to do something like below and append to the above Expression a check if the String property contains a value in the "someStringColumn". Just an insight, the "someStringColumn" will be a general search string on my page past by Ajax on every back-end call.

var properties = item.GetType().GetProperties().Where( p => p.PropertyType == typeof( string ) ).ToArray();

for ( Int32 i = 0; i < properties.Length; i++ )
{

}

I'm trying to achieve something like this in a non-generic method:

    public override List<TableInDatabase> List( PagingModel pm, CustomSearchModel csm )
    {
                String[] qs = ( pm.Query ?? "" ).Split( ' ' );

                return context.TableInDatabase
                              .Where( t => ( qs.Any( q => q != "" ) ? qs.Contains( t.ColumnName) : true ) )
                              .OrderBy( String.Format( "{0} {1}", pm.SortBy, pm.Sort ) )
                              .Skip( pm.Skip )
                              .Take( pm.Take )
                              .ToList();
   }

If I understand correctly, you are seeking for something like this:

var item = Expression.Parameter(typeof(T), "item");
Expression body = Expression.Equal(Expression.Property(item, "Id"), Expression.Constant(id));
if (!string.IsNullOrEmpty(someStringColumn))
{
    var properties = typeof(T).GetProperties().Where(p => p.PropertyType == typeof(string)).ToList();
    if (properties.Any())
        body = Expression.AndAlso(body,
            properties.Select(p => (Expression)Expression.Call(
                Expression.Property(item, p), "Contains", Type.EmptyTypes, Expression.Constant(someStringColumn))
            ).Aggregate(Expression.OrElse));
}       
var whereExpression = Expression.Lambda<Func<T, bool>>(body, item);

ie build Contains expression for each string property, combine them using Or and finally combine the result with the first condition using And .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM