LINQ : How to check CONTAINS with multiple dynamic input values - linq

I am facing a problem regarding a LINQ query.
I have multiple input values which is stored in List< string > variable.
I have to form a LINQ query which would have a where clause which check for the respective column with CONTAINS keyword. The issue I am facing is that List< string > can contain any number of values in it.
So i want to know how can i form a query which can read input values from collection object. and display the result.
Any suggestion would be appreciated.
Thanks in advance.

Linq extension method:
public static bool ContainsAny<T>(this IEnumerable<T> Collection, IEnumerable<T> Values)
{
return Collection.Any(x=> Values.Contains(x));
}
Then you can use like:
List<string> List1 = getStringList1();
List<string> List2 = getStringList2();
bool List2ItemsInList1 = List1.ContainsAny(List2);

Your question is not clear. Suppose you have three values X, Y and Z. If you want to fetch the results where a Column is either X, Y or Z, then habib-osu's answer will do this.
If you are looking for all records where a particular column contains X, Y and Z then the following should work
List<string> options = new List<string>();
options.Add("X");
options.Add("Y");
options.Add("Z");
var query = (from r in dc.Table select r);
foreach(var option in options)
query = (from r in query where r.Column.Contains(option) select r);
var list = query.ToList();
This will produce one sql query similar to the following
select * from Table where Column like '%X%' and column like '%Y%' and column like '%Z%'

Related

Dynamic Linq on DataTable error: no Field or Property in DataRow, c#

I have some errors using Linq on DataTable and I couldn't figure it out how to solve it. I have to admit that i am pretty new to Linq and I searched the forum and Internet and couldn't figure it out. hope you can help.
I have a DataTable called campaign with three columns: ID (int), Product (string), Channel (string). The DataTable is already filled with data. I am trying to select a subset of the campaign records which satisfied the conditions selected by the end user. For example, the user want to list only if the Product is either 'EWH' or 'HEC'. The selection criteria is dynaically determined by the end user.
I have the following C# code:
private void btnClick()
{
IEnumerable<DataRow> query =
from zz in campaign.AsEnumerable()
orderby zz.Field<string>("ID")
select zz;
string whereClause = "zz.Field<string>(\"Product\") in ('EWH','HEC')";
query = query.Where(whereClause);
DataTable sublist = query.CopyToDataTable<DataRow>();
}
But it gives me an error on line: query = query.Where(whereClause), saying
No property or field 'zz' exists in type 'DataRow'".
If I changed to:
string whereClause = "Product in ('EWH','HEC')"; it will say:
No property or field 'Product' exists in type 'DataRow'
Can anyone help me on how to solve this problem? I feel it could be a pretty simple syntax change, but I just don't know at this time.
First, this line has an error
orderby zz.Field<string>("ID")
because as you said, your ID column is of type int.
Second, you need to learn LINQ query syntax. Forget about strings, the same way you used from, orderby, select in the query, you can also use where and many other operators. Also you'll need to learn the equivalent LINQ constructs for SQL-ish things, like for instance IN (...) is mapped to Enumerable.Contains etc.
With all that being said, here is your query
var productFilter = new[] { "EWH", "HEC" };
var query =
from zz in campaign.AsEnumerable()
where productFilter.Contains(zz.Field<string>("Product"))
orderby zz.Field<int>("ID")
select zz;
Update As per your comment, if you want to make this dynamic, then you need to switch to lambda syntax. Multiple and criteria can be composed by chaining multiple Where clauses like this
List<string> productFilter = ...; // coming from outside
List<string> channelFilter = ...; // coming from outside
var query = campaign.AsEnumerable();
// Apply filters if needed
if (productFilter != null && productFilter.Count > 0)
query = query.Where(zz => productFilter.Contains(zz.Field<string>("Product")));
if (channelFilter != null && channelFilter.Count > 0)
query = query.Where(zz => channelFilter.Contains(zz.Field<string>("Channel")));
// Once finished with filtering, do the ordering
query = query.OrderBy(zz => zz.Field<int>("ID"));

Linq to dataset on dynamic columns and dynamic group by fields

I have four parameters to my function a dataset, array consisting of expressions (aggregate functions), array consisting of column names on which to apply expressions and an array consisting of columns on which I have to group by.
My problem is how can I handle dynamic columns or fields for expression and group by as it can vary in numbers (depends on array values).
I have written code for static query, but need a generic way...
This is my code:
public void ExpressionManipulation(DataSet dsExprEvaluate, string[] strExpressions, string[] colName, string[] groupbyFields)
{
int groupByLength = groupbyFields.Length;
var groupByQueryEvaluate = from table in dsExprEvaluate.AsEnumerable()
group table by new { column1 = table["DataSourceType"], column2 = table["Polarity"] }
into groupedTable
select new
{
x = groupedTable.Key, // Each Key contains column1 and column2
y = groupedTable.Count(),
//z = groupedTable.Max(column1),
z = groupedTable.Sum(table => Convert.ToInt32(table["Polarity"]))
};
}
Like in above I can have n number of fields in group by like for now I have taken only two (DataSourceType and Polarity) and similar I can have n number of fields for expressions, for sum, count etc which will be as an array as parameter.
Please help me through this, it is driving me crazy.
Thanks in advance.
I figured it out myself and the solution i ended up is with:
var objGroupSumCountkey = dt.AsEnumerable()
.AsQueryable()
.GroupBy("new ( it[\"DataSourceType\"] as GroupByColumnName1,it[\"Polarity\"] as GroupByColumnName2)", "it")
.Select("new ( Sum(Convert.ToDouble(it[\"Polarity\"].ToString())) as SumValue,Count() as TotalCount,it.key)");
in the above query all the parameters will be supplied as string, in Group By and select

LINQ Distinct set by column value

Is there a simple LINQ query to get distinct records by a specific column value (not the whole record)?
Anyone know how i can filter a list with only distinct values?
You could use libraries like morelinq to do this. You'd be interested in the DistinctBy() method.
var query = records.DistinctBy(record => record.Column);
Otherwise, you could do this by hand.
var query =
from record in records
group record by record.Column into g
select g.First();
Select a single value first and then run the Distinct.
(from item in table
select item.TheSingleValue).Distinct();
If you want the entire record you need to use group x by into y. You then need to find a suitable aggregate function like First, Max, Average or similar to select one of the other values in the group.
from item in table
group item by item.TheSingleValue into g
select new { TheSingleValue = g.Key, OtherValue1 = g.First().OtherValue1, OtherValue2 = g.First().OtherValue2 };
You could make an implementation of the IEqualityComparer interface:
public class MyObjectComparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.ColumnNameProperty == y.ColumnNameProperty;
}
public int GetHashCode(MyObject obj)
{
return obj.ColumnNameProperty.GetHashCode();
}
}
And pass an instance into the Distinct method:
var distinctSource = source.Distinct(new MyObjectComparer());

Longish LINQ query breakes SQLite-parser - simplify?

I'm programming a search for a SQLite-database using C# and LINQ.
The idea of the search is, that you can provide one or more keywords, any of which must be contained in any of several column-entries for that row to be added to the results.
The implementation consists of several linq-queries which are all put together by union. More keywords and columns that have to be considered result in a more complicated query that way. This can lead to SQL-code, which is to long for the SQLite-parser.
Here is some sample code to illustrate:
IQueryable<Reference> query = null;
if (searchAuthor)
foreach (string w in words)
{
string word = w;
var result = from r in _dbConnection.GetTable<Reference>()
where r.ReferenceAuthor.Any(a => a.Person.LastName.Contains(word) || a.Person.FirstName.Contains(word))
orderby r.Title
select r;
query = query == null ? result : query.Union(result);
}
if (searchTitle)
foreach (string word in words)
{
var result = from r in _dbConnection.GetTable<Reference>()
where r.Title.Contains(word)
orderby r.Title
select r;
query = query == null ? result : query.Union(result);
}
//...
Is there a way to structure the query in a way that results in more compact SQL?
I tried to force the creation of smaller SQL-statments by calling GetEnumerator() on the query after every loop. But apparently Union() doesn't operate on data, but on the underlying LINQ/SQL statement, so I was generating to long statements regardless.
The only solution I can think of right now, is to really gather the data after every "sub-query" and doing a union on the actual data and not in the statement. Any ideas?
For something like that, you might want to use a PredicateBuilder, as shown in the chosen answer to this question.

How do I use LINQ to obtain a unique list of properties from a list of objects?

I'm trying to use LINQ to return a list of ids given a list of objects where the id is a property. I'd like to be able to do this without looping through each object and pulling out the unique ids that I find.
I have a list of objects of type MyClass and one of the properties of this class is an ID.
public class MyClass
{
public int ID { get; set; }
}
I want to write a LINQ query to return me a list of those Ids.
How do I do that, given an IList<MyClass> such that it returns an IEnumerable<int> of the ids?
I'm sure it must be possible to do it in one or two lines using LINQ rather than looping through each item in the MyClass list and adding the unique values into a list.
IEnumerable<int> ids = list.Select(x=>x.ID).Distinct();
Use the Distinct operator:
var idList = yourList.Select(x=> x.ID).Distinct();
Using straight LINQ, with the Distinct() extension:
var idList = (from x in yourList select x.ID).Distinct();
When taking Distinct, we have to cast into IEnumerable too. If the list is <T> model, it means you need to write code like this:
IEnumerable<T> ids = list.Select(x => x).Distinct();
int[] numbers = {1,2,3,4,5,3,6,4,7,8,9,1,0 };
var nonRepeats = (from n in numbers select n).Distinct();
foreach (var d in nonRepeats)
{
Response.Write(d);
}
Output
1234567890

Resources