LINQ to SQL create query from string - c#

I have a dbml context query that looks something like this:
var SQLQueryResult = (from activeTable in context.activeTabless
where (
activeTable .AssignedTo == "Person1" ||
activeTable .AssignedTo == "Person2" ||
activeTable .AssignedTo == "Person3")
select new { ... });
My question is, how can I update the where field so that it can have any number of or (not just three as above) based on a user selection?
Let's say the number can come from a list or array.
That's simple with straight SQL but not sure how to do it via Linq to SQL.

var persons = new []{"Person1", "Person2", "Person3"};
var SQLQueryResult = (from activeTable in context.activeTabless
where ( persons.Contains(activeTable .AssignedTo))
select new { ... });
You can check if something exists in a collection using the .Contains() extension method of IEnumerable.

You can create your query dynamically by using Expressions for being able to build where predicates. More details and a sample you can find here: Linq dynamic queries

You can use predicate builder (utility class):
using System;
using System.Linq;
using System.Linq.Expressions;
public static class PredicateBuilder {
public static Expression<Func<T, bool>> Make<T>() {
return null;
}
public static Expression<Func<T, bool>> Make<T>(this Expression<Func<T, bool>> predicate) {
return predicate;
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> orExpression) {
if (expr == null) {
return orExpression;
}
var invokedExpr = Expression.Invoke(orExpression, expr.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.Or(expr.Body, invokedExpr), expr.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, bool>> andExpression) {
if (expr == null) {
return andExpression;
}
var invokedExpr = Expression.Invoke(andExpression, expr.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.And(expr.Body, invokedExpr), expr.Parameters);
}
}
Usage:
public IEnumerable<Squad> GetSquadsByIDs(IEnumerable<int> squadIDs) {
if (squadIDs == null || !squadIDs.Any()) {
throw new ArgumentNullException("squadIDs");
}
var condition = PredicateBuilder.Make<Squad>(s => false);
foreach (var squadID in squadIDs) {
int squadIDValue = squadID;
condition = PredicateBuilder.Or<Squad>(condition, s => s.SquadID == squadIDValue);
}
var db = m_DalContextProvider.GetContext();
return db.Squads.Where(condition);
}

Related

How to write string.Contains(someText) in expression Tree

This is the tutorial I'm following to learn Expression Tree.
I've more than 35 columns to display, but the user can chose to display 10 columns at once. So one the user type something in the search box, I want to search only the columns that are visible to the user.
SELECT FirstName, LastName, Address, ..., State
FROM Students
WHERE Id == #Id col1 AND (
FirstName LIKE '%#searchText%' OR
LastName LIKE '%#searchText%' OR
Address LIKE '%#searchText%' OR
...
State LIKE '%#searchText%')
Back to Linq, this is how I'm trying to accomplish it:
var result = db.Students
.Where(GetPredicate(id, listOfColumns))
.ToList();
This the private method:
private Expression<Func<Student, bool>> GetPredicate(int id, List<string> listOfColumns)
{
ParameterExpression pe = Expression.Parameter(typeof(Student), "s");
Expression left0 = Expression.Property(pe, "Id");
Expression right0 = Expression.Constant(id);
Expression e0 = Expression.Equal(left0, right0);
//Here ... omitted code because it's not working...
//
var expr = Expression.Lambda<Func<Student, bool>>(e0, new ParameterExpression[] { pe });
return expr;
}
As it is above, it's working just fine. However, the reason I even wrote this method was to be able to filter only by the user-selected columns.
I want to be able to compose based on the column that are visible in the UI.
if(!string.IsNullOrEmpty(searchText))
{
foreach (string columnName in columnList)
{
Expression col = Expression.Property(pe, columnName);
Expression left = Expression.Call(pe, typeof(string).GetMethod("Contains"));
Expression right = Expression.Constant(searchText);
Expression e = Expression.IsTrue(left, right);
}
}
I'm completely lost. I know that I need to access the Contains method of the string class then I don't know what next. The Idea is to get something like this:
Where(d => d.Id == id && (d.FirstName.Contains(searchText)
|| d.LastName.Contains(searchText)
|| ...
|| d.State.Contains(searchText)))
Thanks for helping
You are pretty close, except constructing the call of Contains does not have a right side:
Expression col = Expression.Property(pe, columnName);
Expression contains = Expression.Call(
pe
, typeof(string).GetMethod(nameof(string.Contains), new Type[] { typeof(string)}) // Make a static field out of this
, Expression.Constant(searchText) // Prepare a shared object before the loop
);
Once you have your call expressions, combine them with OrElse to produce the body of your lambda. You can do it with loops, or you can use LINQ:
private static readonly MethodInfo Contains = typeof(string)
.GetMethod(nameof(string.Contains), new Type[] { typeof(string)});
public static Expression<Func<Student,bool>> SearchPredicate(IEnumerable<string> properties, string searchText) {
var param = Expression.Parameter(typeof(Student));
var search = Expression.Constant(searchText);
var components = properties
.Select(propName => Expression.Call(Expression.Property(param, propName), Contains, search))
.Cast<Expression>()
.ToList();
// This is the part that you were missing
var body = components
.Skip(1)
.Aggregate(components[0], Expression.OrElse);
return Expression.Lambda<Func<Student, bool>>(body, param);
}
I like the PredicateBuilder class for stuff like this scenario:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T> () { return f => true; }
public static Expression<Func<T, bool>> False<T> () { return f => false; }
public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}
Code using this would look like:
var predicate = PredicateBuilder.True<Student>().And(i=>i.Id==id);
if(!string.IsNullOrEmpty(searchText))
{
if (firstNameColumnVisible) {
predicate = predicate.And(i=>i.FirstName.Contains(searchText));
}
if (lastNameColumnVisible) {
predicate = predicate.And(i=>i.LastName.Contains(searchText));
}
// more columns here.
}
At the end, use the PredicateBuilder instance as arguments to your Where operator in the Linq query.

Can't translate LINQ In clause over EF

I need to translate this simple SQL query into LINQ using EF entities:
SELECT * FROM Clientes WHERE ID_Cliente IN(SELECT ID_Objeto FROM
Direcciones where ID_TipoDireccion=IDTipoDireccion)
Seems very simple, but it seems to be a very hard to achieve. I try this:
public List<Clientes> EnumEntity(int IDTipoDireccion)
{
var dir = new DireccionesRepository(ref rep.Context);
var misClientes = rep.ListEntity();
var misDirColection = dir.ListEntity().ToList().Where(o => o.ID_TipoDireccion == IDTipoDireccion);
foreach (var item in misDirColection)
{
misClientes=misClientes.Where(p => p.ID_Cliente == item.ID_Objeto);
}
return misClientes.ToList();
}
The problem with above query is that use AND. I need it to use OR to include all clients that matches Direcciones object.
I try PredicateBuilder class but it doesn't support EF. I found this adaptation of PredicateBuilder that seems to resolve this problem:
internal class SubstExpressionVisitor : System.Linq.Expressions.ExpressionVisitor
{
public Dictionary<Expression, Expression> subst = new Dictionary<Expression, Expression>();
protected override Expression VisitParameter(ParameterExpression node)
{
Expression newValue;
if (subst.TryGetValue(node, out newValue))
{
return newValue;
}
return node;
}
}
public static class PredicateBuilder
{
/*public static Expression<Func<T,bool>> True<T>() { return f => true; }*/
//public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> a, Expression<Func<T, bool>> b)
{
ParameterExpression p = a.Parameters[0];
SubstExpressionVisitor visitor = new SubstExpressionVisitor();
visitor.subst[b.Parameters[0]] = p;
Expression body = Expression.AndAlso(a.Body, visitor.Visit(b.Body));
return Expression.Lambda<Func<T, bool>>(body, p);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> a, Expression<Func<T, bool>> b)
{
ParameterExpression p = a.Parameters[0];
SubstExpressionVisitor visitor = new SubstExpressionVisitor();
visitor.subst[b.Parameters[0]] = p;
Expression body = Expression.OrElse(a.Body, visitor.Visit(b.Body));
return Expression.Lambda<Func<T, bool>>(body, p);
}
}
But the problem is I don't know how to use it in my case.
Can anybody help me?
Thanks!
EDIT
After adapting the suggested code, this is the result in case someone else need it:
public List<EnumeradorWCFModel> EnumEntity(int IDTipoDireccion)
{
// SELECT * FROM Clientes WHERE ID_Cliente IN(SELECT ID_Objeto FROM Direcciones where ID_TipoDireccion=IDTipoDireccion)
// Get All directions of type IDTipoDireccion
var dir = new DireccionesRepository(ref rep.Context);
var misDirColection = dir.ListEntity().Where(x => x.ID_TipoDireccion == IDTipoDireccion)
.Select(x => x.ID_Objeto); // Do not iterate!
// Itinerate Clients
var misClientes = rep.ListEntity().Where(x => misDirColection.Contains(x.ID_Cliente)).ToList();
return misClientes.ToList();
}
Use Contains().
SELECT * FROM Clientes WHERE ID_Cliente IN(SELECT ID_Objeto FROM Direcciones where ID_TipoDireccion=IDTipoDireccion)
Can be directly translated to:
int IDTipoDireccion = ...
// First, create a query for your subselect.
var direcciones = dbContext.Direcciones
.Where(x => x.ID_TipoDireccion == IDTipoDireccion);
.Select(x => x.ID_Objeto); // Do not iterate!
// Then, use the first query in the WHERE of your second query.
var results = dbContext.Clientes
.Where(x => direcciones.Contains(x.ID_Cliente))
.ToList();

LINQ query to combine 2 resultsets

I have a C# LINQ query that has a main query and then 2 other queries depending on if a variable is not set 0.
The query is working, but I need to combine the resultsets and return that.
I want the final resultset to contain the results of the two subqueries combined. Kind of like in a SQL query where you have:
SELECT * FROM myTable WHERE column1 = 'abc' OR column2 = 'xyz'
Right now, I think it's using an AND instead of an OR
var GeoLocations = rows.Select(r => new ElementSearchGeoLocation(r))
.Where(t => (t.GeoLocationType == "State" && t.CanViewState(t.GeoLocationState, user)) ||
(t.GeoLocationType == "City" && t.CanViewCity(t.GeoLocationCity, user)));
if(SystemList != 0)
{
GeoLocations = GeoLocations.Where(t => (dto.SystemList.Contains(t.SystemID)));
}
if (groupList != 0)
{
GeoLocations = GeoLocations.Where(t => (dto.groupList.Contains(t.PoliticalID)));
}
return Ok(GeoLocations);
Is there a way to do this in LINQ?
Here is an implementation of a PredicateBuilder that is able to Or together two different expressions:
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(
expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(
expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
}
It's dependant on the following code to be able to replace all instances of one expression with another:
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
internal static class ExpressionExtensions
{
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
}
Using this you can now write:
var GeoLocations = rows.Select(r => new ElementSearchGeoLocation(r))
.Where(t => (t.GeoLocationType == "State" && t.CanViewState(t.GeoLocationState, user)) ||
(t.GeoLocationType == "City" && t.CanViewCity(t.GeoLocationCity, user)));
var predicate = PredicateBuilder.False();
if(SystemList != 0)
{
predicate = predicate.Or(t => dto.SystemList.Contains(t.SystemID));
}
if (groupList != 0)
{
predicate = predicate.Or(t => dto.groupList.Contains(t.PoliticalID));
}
return Ok(GeoLocations.Where(predicate));
Use Concat to add in the additional rows. To make the code super minimal, I would store off the initial `Select first:
var AllLocations = rows.Select(r => new ElementSearchGeoLocation(r));
var mainQuery = AllLocations.Where(t => (t.GeoLocationType == "State" && t.CanViewState(t.GeoLocationState, user)) ||
(t.GeoLocationType == "City" && t.CanViewCity(t.GeoLocationCity, user)));
Then:
IEnumerable<GeoLocation> subQuery;
if (SystemList != 0)
subQuery = AllLocations.Where(...);
else
subQuery = AllLocations.Where(...);
var GeoLocations = mainQuery.Concat(subQuery);
If you care about duplicates, you can use Union instead of Concat for the last step.
Two methods come up for this behaviour
Union, which combines two result sets while culling for duplicates
Concat, which simply slams two result sets together
Which one you choose depends on desired behaviour. Note that either of these may or may not work if your queries are actually IQueryables and running from a database (via linq-to-sql or Entity Framework or the like).
As has been mentioned, do not forget that LINQ results are lazily-evaluated, and this parts of a query can be safely saved and rehashed for later.

Dynamic Linq query on List <T> using Predicate Builder

I'm using C# 2010 .NET 4.0 and I have a List<T> collection called returns that I need to build a dynamic LINQ query on.
I'm utilizing the Predicate Builder referenced here.
This works fine if I have 1 filter criteria, but if I have 2 or more, then, when the query.compile() is called, I get this error:
variable 'tmp' of type 'Check21Tools.IncomingReturn' referenced from
scope '', but it is not defined
Code:
Expression<Func<Check21Tools.IncomingReturn, bool>> query = null;
bool hasFilterItems = false;
if (filterArray != null)
{
foreach (string s in filterArray)
{
if (s == string.Empty)
{ break; }
else
{
hasFilterItems = true;
Int64 id = Int64.Parse(s);
query = query.Or(tmp => tmp.ID == id);
}
}
}
if (hasFilterItems)
{
returns = returns.Where(query.Compile()).CreateFromEnumerable
<Check21Tools.IncomingReturns, Check21Tools.IncomingReturn>();
}
Code:
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
if (expr1 == null) return expr2;
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, expr2.Body), expr1.Parameters);
}
[The OP has] stumbled across an updated version of the predicate builder that works on List<T> objects:
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
if (expr1 == null) return expr2;
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}

Dynamic Where condition with Queryover

I have an application and I'm trying to implement DDD concepts. I have my repository class with some method to list entities. I would like to know how can I do a query with QueryOver to filter separating with AND operator, when the parameter is filled, sample
public IEnumerable<Product> FindProducts(string name, decimal? price, DateTime? validDate, int? stock, int? idSupplier)
{
var query = Session.QueryOver<Product>().OrderBy(x => x.Name).Asc;
if (!string.IsNullOrEmpty(name))
// add where condition for name parameter
if (price.HasValue)
// add 'AND' where condition for price parameter
if (validDate.HasValue)
// add 'AND' where condition for validDate parameter
if (idSupplier.HasValue)
// add 'AND' where condition for idSupplier parameter
// other possible conditions
return query.List();
}
Is there any way to do that before I use HQL string query? hehehe
Thank you!
Here, use PredicateBuilder:
How To:
IQueryable<Product> SearchProducts (params string[] keywords)
{
var predicate = PredicateBuilder.False<Product>();
foreach (string keyword in keywords)
{
string temp = keyword;
predicate = predicate.Or (p => p.Description.Contains (temp));
}
return dataContext.Products.Where (predicate);
}
PredicateBuilder Source:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T> () { return f => true; }
public static Expression<Func<T, bool>> False<T> () { return f => false; }
public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}
For more information on PredicateBuilder and LinqKit go here: http://www.albahari.com/nutshell/linqkit.aspx

Categories

Resources