Search multiple values in one column - linq

How to select record based on multiple values search in one column using linq query.
like product id is "product1", "product2","product3" n number of values we have

You can use the .Contains method to check whether a value is within a list.
var values = new List<string>() { "Prod1", "Prod2", "Prod3" };
var query = context.Set<Product>().Where(x => values.Contains(x.Name));

You could use something like (this is VB.Net, change to C# if necessary)
Dim result = products.Where(Function(p) p.ID = "product1" Or p.ID = "product2" Or p.ID = "product3", ...)
Alternatively, you could pull it all back to the client and use .Contains, like so:
Dim materializedProducts = products.ToList()
Dim result = materializedProducts.Where(Function(p) {"product1", "product2", "{product3}", ...}.Contains(p.ID))
Going further still, you could create an extension method (generic, if that floats your boat) called IsIn or similar that allows you to swap the order of the collection and the search value:
<Extension()>
Public Function IsIn(Of T)(ByVal searchValue As T,
ByVal searchSet As IEnumerable(Of T))
Return searchset.Contains(searchValue)
End Sub
Dim materializedProducts = products.ToList()
Dim result = materializedProducts.Where(Function(p) p.ID.IsIn({"product1", "product2", "{product3}", ...}))

Related

Filter generic list (comma separated values)

I want to filter list as below. I have a class & I want to filter values from that are in my filter string. I have achieved my result by a for loop but need a way without for loop.
Public Class WorkStationDetails<br><br>
Property CountryId As Integer<br>
Property CountryName As String<br>
Property TotalWrkStn As Integer<br>
Property ExistingWrkStn As Integer<br>
Property RemainingWrkStn As Integer<br><br>
End Class
Dim WrkStnDtl As List(Of WorkStationDetails)
Dim FilterWrkStnDtl As List(Of WorkStationDetails)
Dim Numbers As String()
Numbers = "1,5,6,2,9".Split(",")
For i As Integer = 0 To Numbers.Length - 1
FilterWrkStnDtl.AddRange(WrkStnDtl.FindAll(Function(p) (p.CountryId = Numbers(i))))
Next
Note: I want to achieve it like subquery in sql server.
I think you want something like this"
var numbers = "1,5,6,2,9".Split(',');
var selected = WrkStnDtl.Where(w => numbers.Contains(w.CountryId)).ToList();

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".

LINQ create multiple new entities using a single ID field

I have a newbie LINQ question. I need to create two objects of same type from a list of strings. I need to append a text 'Direct' & "Indirect' to the string and use them as ID to create the two unique objects.
var vStrings = new List { "Milk", "Eggs", "Cheese" };
var vProducts = (from s in vStrings
select new Product { ID = s + "-Direct" })
.Union(
from s in vStrings
select new Product { ID = s + "-InDirect" });
You can see in the example above, I am using a Union to create two different objects, Is there a better way to rewrite this LINQ query?
Thanks for your suggestions
If you ever needed more suffixes, this might be a better way:
var strings = new List<string> { "Milk", "Eggs", "Cheese" };
var suffixes = new List<string> {"-Direct", "-InDirect"};
var products = strings
.SelectMany(_ => suffixes, (x, y) => new Product() {ID = x + y});
And it would only iterate over the original set of strings once.
This way isn't much shorter but I think it would be a little better such as there is only one Concat instead of many Union:
var vProducts2 = (from s in vStrings
select s + "-Direct").Concat(
from s in vStrings
select s + "-InDirect");

LINQ: Entity string field contains any of an array of strings

I want to get a collection of Product entities where the product.Description property contains any of the words in a string array.
It would look something like this (result would be any product which had the word "mustard OR "pickles" OR "relish" in the Description text):
Dim products As List(Of ProductEntity) = New ProductRepository().AllProducts
Dim search As String() = {"mustard", "pickles", "relish"}
Dim result = From p In products _
Where p.Description.Contains(search) _
Select p
Return result.ToList
I already looked at this similar question but couldn't get it to work.
Since you want to see if search contains a word which is contained in the description of p you basically need to test for each value in search if it is contained in the description of p
result = from p in products
where search.Any(val => p.Description.Contains(val))
select p;
This is c# syntax for the lambda method since my vb is not that great
Dim result = From p in products _
Where search.Any(Function(s) p.Description.Contains(s))
Select p
You can use a simple LINQ query, if all you need is to check for substrings:
var q = words.Any(w => myText.Contains(w));
// returns true if myText == "This password1 is weak";
If you want to check for whole words, you can use a regular expression:
Matching against a regular expression that is the disjunction of all the words:
// you may need to call ToArray if you're not on .NET 4
var escapedWords = words.Select(w => #"\b" + Regex.Escape(w) + #"\b");
// the following line builds a regex similar to: (word1)|(word2)|(word3)
var pattern = new Regex("(" + string.Join(")|(", escapedWords) + ")");
var q = pattern.IsMatch(myText);
Splitting the string into words with a regular expression, and testing for membership on the words collection (this will get faster if you use make words into a HashSet instead of a List):
var pattern = new Regex(#"\W");
var q = pattern.Split(myText).Any(w => words.Contains(w));
In order to filter a collection of sentences according to this criterion all you have to do its put it into a function and call Where:
// Given:
// bool HasThoseWords(string sentence) { blah }
var q = sentences.Where(HasThoseWords);
Or put it in a lambda:
var q = sentences.Where(s => Regex.Split(myText, #"\W").Any(w => words.Contains(w)));
Ans From => How to check if any word in my List<string> contains in text by #R. Martinho Fernandes

Unable to cast object

I am new to LINQ, I tried to run the following code and I got InvalidCastException error: "Unable to cast object of type 'd__3a`1[debug.Product]' to type 'debug.Product'" - what is wrong?
Code (VB - using VS2008)
Private Sub btnLinq_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLinq.Click
Dim Products As New List(Of Product)
Dim p1 As New Product
p1._ID = "1"
p1._Name = "Product A"
Products.Add(p1)
Dim p2 As New Product
p2._ID = "2"
p2._Name = "Product B"
Products.Add(p2)
Dim p3 As New Product
p3._ID = "3"
p3._Name = "Product C"
Products.Add(p3)
Dim prod As Product = From p In Products Where p._ID = "1" Select p Take 1
MsgBox(prod._ID)
End Sub
End Class
Public Class Product
Public _ID As String
Public _Name As String
End Class
Take returns an IEnumerable<Product> (in your case), and not a Product.
(Check it by outputting result.GetType() ):
(note that my example code is in C#)
List<Product> products = new List<Product> ();
products.Add (new Product ()
{
Id = 1,
Name = "Prod1"
});
products.Add (new Product ()
{
Id = 2,
Name = "Prod2"
});
var result = ( from p in products
where p.Id == 1
select p ).Take (1);
Console.WriteLine (result.GetType ());
Console.ReadLine ();
In my case, the code above outputs:
System.Linq.Enumerable+<TakeIterator>d__3a`1[LinqTest.Product]
In your case, instead of using Take 1, you could try to use First or FirstOrDefault instead.
So, try this:
var result = ( from p in products
where p.Id == 1
select p ).FirstOrDefault ();
Console.WriteLine (result.GetType ());
Console.WriteLine (result.Name);
The Take method (Enumerable.Take) doesn't return an element, rather it returns an another sequence (IEnumerable<Product>). Take(n) just creates a new sequence with a maximum of n elements.
To take the first element from the sequence use one of the following methods:
FirstOrDefault() - returns null if the sequence is empty
First() - throws InvalidOperationException if the sequence is empty

Resources