Is there a pattern using Linq to dynamically create a filter? - linq

Is there a pattern using Linq to dynamically create a filter?
I have the need to create custom filtering on a list, in the past I would just dynamically create the SQL...it doesn't seem like this is possible with Linq.

Check out the Dynamic Linq Library from ScottGu's blog:
For example, below is a standard type-safe LINQ to SQL VB query that retrieves data from a Northwind database and displays it in a ASP.NET GridView control:
Dim Northwind As New NorthwindDataContext
Dim query = From q In Northwind.Products Where p.CategoryID = 2 And p.UnitPrice > 3 Order By p.SupplierID Select p
Gridview1.DataSource = query
GridView1.DataBind()
Using the LINQ DynamicQuery library I could re-write the above query expression instead like so
Dim Northwind As New NorthwindDataContext
Dim query = Northwind.Products .where("CategoryID=2 And UnitPrice>3") . OrderBy("SupplierId")
Gridview1.DataSource = query
GridView1.DataBind()
Notice how the conditional-where clause and sort-orderby clause now take string expressions instead of code expressions. Because they are late-bound strings I can dynamically construct them. For example: I could provide UI to an end-user business analyst using my application that enables them to construct queries on their own (including arbitrary conditional clauses).

Dynamic Linq is one way to go.
It may be overkill for your scenario. Consider:
IQueryable<Customer> query = db.Customers;
if (searchingByName)
{
query = query.Where(c => c.Name.StartsWith(someletters));
}
if (searchingById)
{
query = query.Where(c => c.Id == Id);
}
if (searchingByDonuts)
{
query = query.Where(c => c.Donuts.Any(d => !d.IsEaten));
}
query = query.OrderBy(c => c.Name);
List<Customer> = query.Take(10).ToList();

Dynamically Composing Expression Predicates

something like this?
var myList = new List<string> { "a","b","c" };
var items = from item in db.Items
where myList.Contains(item.Name)
select item;
that would create a sql statement like
SELECT * FROM Items [t0] where Name IN ('a','b','c')

Related

How to set Filter Values in LinQ with SQL Query Text?

I am using LINQ for my database application.
So I can write things like:
using (ShuttleDataContext dc = Config.GetNewShuttleDBConnection())
{
List<RefState> states = (from a in dc.RefStates select a).ToList();
return states;
}
Know I have to handle the requierement, that I have to filter from this database by SQL strings, e.g. a filter string: "ID like '7%'" or "Name = 'Red'".
Of course normaly I would write something like .Where(a => a.Name == "Red"), but it's nearly impossible to map every filterexpression to a where clause... So is there a method to have native T-SQL in an Linq-List?
As far as I know you can't just provide the filter condition, but you can use ExecuteQuery to execute an arbitrary SQL statement and map that to your LINQ types:
List<RefState> states = dc.ExecuteQuery<RefState>(
"SELECT * FROM RefStates WHERE ID LIKE '7%'").ToList();

How to select mutiple rows from Entity using Linq

I want write a LINQ query equivalent to
select * from Users
where Username in ('something#somewhere.com', 'someone#somehting.com')
Is it possible to write this in LINQ?
In order to replicate the functionality of IN clauses you have to have (or create) a collection and check whether that collection contains the value you're looking for.
var search = new string[] {"something#somewhere.com", "someone#somehting.com"};
var results = Users.Where(u => search.Contains(u.Username));
Or, you can use a very lazy solution
DbEntities db = new DbEntities();
var users = db.Users.where(u => u.Username == "something#somewhere.com" || u.Username == "someone#somehting.com");
Very lazy (Easily understudy by beginner LINQ developer).

how to use a dynamic variable in orderby clause

am a newbie in linq.. am stuck with one scenario. ie,
i have to sort the search results based on user input.
user inputs are Last Name, First Name and Title. for input 3 drop downs are there and i have to sort result based on the values selected.
i tried
order = Request["orders"].Split(',');
var param = order[0];
var p1 = typeof(Test).GetProperty(param);
param = order[1];
var p2 = typeof(Test).GetProperty(param);
param = order[2];
var p3 = typeof(Test).GetProperty(param);
model.Test = (from tests in model.Test
select tests).
OrderBy(x => p1.GetValue(x, null)).
ThenBy(x => p2.GetValue(x, null)).
ThenBy(x => p3.GetValue(x, null));
but it doesn't works.
i want qry like this
from tests in model.Test
select tests).OrderBy(x => x.lastname).
ThenBy(x => x.firstname).ThenBy(x => x.Title);
order[0]== lastname but how can i use it in the place of OrderBy(x => x.order[0])..?
Thanks in advance.
i solved my case as follows
// list of columns to be used for sorting
List<string>order = Request["orders"].Split(',').ToList();
//map the column string to property
var mapp = new Dictionary<string, Func<Test, string>>
{
{"FirstName", x => x.FirstName},
{"LastName", x => x.LastName},
{"SimpleTitle", x => x.SimpleTitle}
};
//user inputted order
var paras = new List<Func<Test, string>>();
foreach (var para in order)
{
if(!string.IsNullOrEmpty(para))
paras.Add(mapp[para]);
}
//sorting
model.Test= model.Test.OrderBy(paras[0]).ThenBy(paras[1]).ThenBy(paras[2]);
Thanks all,
Actually you are looking for dynamic linq query than you can try out Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)
which allow to do like this
it means you can dynamically pass string propertyname to short you collection in orderby function
You can also read about : Dynamic query with Linq
You can compose the expression (any Expression) manually from pieces and then append it to the previous part of query. You can find more info, with example in "Sorting in IQueryable using string as column name".

How to get the Entity-SQL command text by LINQ query?

It's an exercise of EF code-first. There's a simple method. I want to get the Entity SQL command text generated by object services.
(MyDbContext is derived form DbContext. Person is a POCO class.)
using (MyDbContext context = new MyDbContext())
{
var query = context.Set<Person>().FirstOrDefault(p => p.Age == 1);
Console.WriteLine(query.Name);
var objquery = query as ObjectQuery;
if (objquery != null)
Console.WriteLine(objquery.CommandText);
}
I used to get native SQL command text by ObjectQuery.TraceString in LINQ to Entity. Now, what I need is Entity-SQL statement, NOT native SQL statement.
But, I can't cast the query from IQueryable<Person> to ObjectQuery or ObjectQuery<Person>.
I tried to get members of DbQuery by reflection. It seems that DbQuery hasn't any property about command text or trace string.
Thanks
My suggestion for what you want is using Dynamic Linq. The library (part of the Linq Samples) includes many IQueryable extensions that return Linq.DataQuery objects. Once you consume the DataQuery you'll have the expected object.
var testQuery =
db.Cases.
Where("KeyID > 1").
Take(1);
foreach (var r in testQuery)
{
Console.WriteLine(r);
}
Then, you can check against your query as such.
testQuery.Expression
testQuery.Provider
These will give you:
{Table(Case).Where( => (.Keyid > 1)).Take(1)}
System.Linq.Expressions.Expression {System.Linq.Expressions.MethodCallExpression}
-and-
{SELECT TOP (1) [t0].[Keyid], [t0].[FileNo], [t0].[MatterType], [t0].[LoanNo], [t0].[Investor], [t0].[LoanType], [t0].[Client], [t0].[ClientFileNo], [t0].[ClientStatus], [t0].[Mortgagor], [t0].[County], [t0].[PropertyStreet1], [t0].[PropertyStreet2], [t0].[PropertyCity], [t0].[PropertyState], [t0].[PropertyZipcode], [t0].[Status], [t0].[BoxNo], [t0].[InsurerLoanno], [t0].[InvestorLoanno], [t0].[insurer_name_id], [t0].[OldSystemKey], [t0].[FinalBilling], [t0].[HoldBilling], [t0].[LastModified], [t0].[PiggyLoanNo], [t0].[CurrComentID], [t0].[LockEFILE], [t0].[MSJAmount], [t0].[Created], [t0].[Locked], [t0].[FinalBillingDate], [t0].[HoldBillingDate], [t0].[CreatedBy], [t0].[Stage], [t0].[PriorStage], [t0].[DefendantUpdated], [t0].[VestingCode], [t0].[FileSource], [t0].[SubVestingCode], [t0].[AttorneyAssigment], [t0].[VoluntarySurrender], [t0].[FNMARisk], [t0].[Source], [t0].[REO_ID], [t0].[WTI_ID], [t0].[CaseDismissed], [t0].[REO_CompanyID], [t0].[SubMattertype], [t0].[VendorCode], [t0].[SubType]
FROM [dbo].[Cases] AS [t0]
WHERE [t0].[Keyid] > #p0}
System.Linq.IQueryProvider {System.Data.Linq.DataQuery<CMSDEVMapping.Case>}
You can also verify your type in the loop:
r.GetType() {Name = "Case" FullName = "CMSDEVMapping.Case"} System.Type {System.RuntimeType}

Building Dynamic LINQ Queries based on Combobox Value

I have a combo box in Silverlight. It has a collection of values built out of the properties of one of my LINQ-to-SQL objects (ie Name, Address, Age, etc...). I would like to filter my results based off the value selected in a combo box.
Example: Say I want everyone with a last name "Smith". I'd select 'Last Name' from the drop down list and enter smith into a textbox control. Normally I would write a LINQ query similar to...
var query = from p in collection where p.LastName == textbox.Text select p;
Is it possible to decide the property dynamically, maybe using Reflection? Something like
var query = from p in collection where p.(DropDownValue) == textbox.Text select p;
Assuming:
public class Person
{
public string LastName { get; set; }
}
IQueryable<Person> collection;
your query:
var query =
from p in collection
where p.LastName == textBox.Text
select p;
means the same as:
var query = collection.Where(p => p.LastName == textBox.Text);
which the compiler translates from an extension method to:
var query = Queryable.Where(collection, p => p.LastName == textBox.Text);
The second parameter of Queryable.Where is an Expression<Func<Person, bool>>. The compiler understands the Expression<> type and generates code to build an expression tree representing the lambda:
using System.Linq.Expressions;
var query = Queryable.Where(
collection,
Expression.Lambda<Func<Person, bool>>(
Expression.Equal(
Expression.MakeMemberAccess(
Expression.Parameter(typeof(Person), "p"),
typeof(Person).GetProperty("LastName")),
Expression.MakeMemberAccess(
Expression.Constant(textBox),
typeof(TextBox).GetProperty("Text"))),
Expression.Parameter(typeof(Person), "p"));
That is what the query syntax means.
You are free to call these methods yourself. To change the compared property, replace this:
typeof(Person).GetProperty("LastName")
with:
typeof(Person).GetProperty(dropDown.SelectedValue);
Scott Guthrie has a short series on dyamically built LINQ to SQL queries:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
That's the easy way...then there's another way that's a bit more involved:
http://www.albahari.com/nutshell/predicatebuilder.aspx
You can also use the library I created: http://tomasp.net/blog/dynamic-linq-queries.aspx. You would store the properties in ComboBox as lambda expressions and then just write:
var f = (Expression<Func<Product, string>>)comboBox.SelectedValue;
var query =
from p in collection
where f.Expand(textBox.Text)
select p;

Resources