I'm using LINQ to search multiple fields on a single phrase and I'm using Contains() to do this. Up until today, when I noticed that the find method isn't working correctly.
So I'd like to be able to search each of the fields where there is any match. I've done some searching on Google and through SO and found suggestions of using Any()? Does anyone have any suggestions?
var l = _getData().Select(_marshallData).ToList();
return l.Where(x => x.Name.Contains(what) || x.Pumpkin.Contains(what) || x.Orange.Contains(what) || x.Tomato.Contains(what)).ToList();
Please excuse the stupid field names, I've had to change them for confidentiality.
Since you're materializing the data already you could do this:
var l = _getData().Select(_marshallData).AsEnumerable();
return l.Where(x => new[] { x.Name, x.Pumpkin, x.Orange, x.Tomato }.Any(s => s.Contains(what)));
But if you're using an ORM (like Entity Framework) this trick probably won't work (since there's a good chance this can't be converted to a SQL expression). In this case, you're original solution is fine, but it would probably be better to do this before you materialize the data.
return _getData()
.Where(x =>
x.Name.Contains(what) || x.Pumpkin.Contains(what) ||
x.Orange.Contains(what) || x.Tomato.Contains(what))
.Select(_marshallData)
.AsEnumerable();
Of course the field names here might be different, since the parameter x is probably a different type. Without further information, it's up to you to write this filter correctly.
Note that in both examples, I've eliminated the calls to ToList. Unless you absolutely need the result to a List<T> this is probably unnecessary.
Related
Please bear with me I'm not to hot on LINQ and even less on C# but I have the following statement that's causing me a headache:
myList = myClass.Where(f => f.OrigiFilename == origiFilename).ToList();
It works okay currently but needs changing.
I understand the where clause returns a result set of filenames and we are going to compare them to the variable
origiFilename
So we essence we are comparing like so: file1.txt == file1, file2.doc == file1, file3.pdf == file1
However, what must happen is we want to ignore the file extension that is returned from
f.OrigiFilename
I'd ideally want to use Get File Name Without Extension but I can't seem to do this in LINQ or be able to switch to C# to do this and then back.
Any LINQ experts out there ever have to do this?
I do have a workaround which is add the lot into the list and then move though the list again removing each using C# but this isn't ideal, I want it all done in one statement...
Do you mean this?
myClass
.Where(f => Path.GetFileNameWithoutExtension(f.OrigiFilename) == origiFilename)
.ToList();
Unfortunately, if you want to keep the query on the database side, there isn't an easy way to jump back to C#, however, you can do the following, which should translate into decent SQL query, albeit there are some differences and will fail if there are multiple extensions on the filename:
myList = myClass.Where(f => f.OrigiFilename.StartsWith(origiFilename+".")).ToList();
The Path class contains a GetFileNameWithoutExtension() method that you can use:
myList = myClass
.Where(f => Path.GetFileNameWithoutExtension(f.OrigiFilename) == origiFilename)
.ToList();
Is that possible in LINQ to write a nice one-liner to get a first matched element or if there's no match than get first element in the collection?
E.g. you have a collection of parrots and you want yellow parrot but if there's no yellow parrots - then any will do, something like this:
Parrots.MatchedOrFirst(x => x.Yellow == true)
I'm trying to avoid double-go to SQL Server and the ORM we use in this particular case is Dapper.
What about:
var matchedOrFirst = Parrots.FirstOrDefault(x => x.Yellow == true)
?? Parrots.FirstOrDefault();
Edit
For structs, this should work:
var matchedOrFirst = Parrots.Any(x => x.Yellow == true)
? Parrots.First(x => x.Yellow == true)
: Parrots.FirstOrDefault();
Edit: It was a linq to SQL solution
First building a handy extension
public static T MatchedOrFirstOrDefault<T>(this IQueryable<T> collection, System.Linq.Expressions.Expression<Func<T, Boolean>> predicate)
{
return (from item in collection.Where(predicate) select item)
.Concat((from item in collection select item).Take(1))
.ToList() // Convert to query result
.FirstOrDefault();
}
Using the code
var matchedOrFirst = Parrots.MatchedOrFirstOrDefault(x => x.Yellow);
If you want to avoid a 2nd SQL call and since requires branching logic, its unlikely that Dapper will know how to convert a LINQ query you come up with into appropriate SQL IIF, CASE, or whatever other SQL-specific functions you end up using.
I recommend you write a simple stored procedure to do that and call it from Dapper.
Depending on its usage though, if this page only has one or two queries on it already, and is located reasonably close (latency wise) to the server, a 2nd simple SELECT won't hurt the overall application that much. Unless it is in a loop or something, or your example is trivial compared to the actual query regarding the cost of the first SELECT.
I currently have the following code:
var FirstNameList = db.Clients.Include(x => x.FirstNames).Include(x => x.Addresses).SelectMany(a => a.FirstNames).Where(x => x.Name.ToLower().Trim() == "Max".ToLower().Trim()).ToList();
I have a navigation property of FirstNames and Addresses which I which to include in the result.
I use the SelectMany Statement because it, for me, is the only one which works. Kind of. It returns all the FirstNames where the Name equals Max.
What I would like it to do is return all the Clients who have the property Name equals Max from the table FirstNames.
the other way I thought about doing this was to take all the ID's returned from FirstNameList and then returning the Clients by querying the data against the FirstNameList but I would be then querying the database twice, which seems inefficient.
My question is is it possible, and how would I go about querying the database to return my Clients, if it was?
Kind regards
The following query should give you what you're looking for. You can look within each client's FirstNames and see if any of them are named "max". (In this case, since "max" is a constant you're typing in, I removed the ToLower().Trim() from it)
var clientsNamedMax = db.Clients.Include(x => x.FirstNames).Include(x => x.Addresses).Where(x => x.FirstNames.Any(y => y.Name.ToLower().Trim() == "max")).ToList();
I'd like to do a LINQ query that can compare multiple variables to a single string. I've seen LINQ for LIKE queries of array elements, and it's helpful, but not quite. I need the reverse.
What I'd like to do is the following: let's say I have a Company object with both Name and Address. I also have a string keyword. Then, I'd like to find all Companys in a list that have the keyword in either their Name or Address. In SQL it would be...
SELECT * FROM Company
WHERE Name LIKE '%keyword%' OR Address LIKE '%keyword%'
I've been using Entity Framework, and I've tried the following: context.Companies.Where(x => new string[] { x.Name, x.Address }.Contains(keyword), as well as context.Companies.Where(x => new string[] { x.Name, x.Address }.Any(r => r.Contains(keyword)), but neither were successful. The first one gives me an IN clause, and the second one... I don't know what it does, but it doesn't give me what I want.
I'm sorry I don't have a very in-depth understanding of Expressions (yet); I wished I was able to write my own custom Expressions from scratch, but scratch it I can't just yet... Can anybody help me with this?
Any reason for not just using the || operator?
context.Companies.Where(x => x.Name.Contains(keyword) ||
x.Address.Contains(keyword))
I'd expect this to be translated into your original SQL.
What is the linq equivalent of a SQL clause like WHERE UserName LIKE 'fr_d'?
I'm working with a dataset in memory rather than a SQL database so I don't think I can use something like where SqlMethods.Like(p.UserName, "Fr_d")
(Not that my installation of VS2008 is admitting that SqlMethods or even System.Data.Linq.SqlClient
exist at the moment, but thats a whole different problem!)
Like this:
table.Where(row => row.StringColumn.StartsWith("prefix"))
(You may also want to call Contains or EndsWith)
EDIT: In your case, you want
table.Where(p => p.UserName.StartsWith("Fr") && p.UserName.EndsWith("d") && p.UserName.Length == 4)
Alternatively, you can also put a regex inside the Where clause.
If you do, make sure to create the RegEx object outside the Where call so that it doesn't get parsed for each row.
I belive this is what you really want. It will allow Fr{any one character}d:
table.Where(p => p.UserName.StartsWith("Fr") && p.UserName.EndsWith("d") && p.UserName.Length == 4 )
Unfortunately I can't find anything that does something similar to SQL's like clause for LINQ to Dataset...
UPDATE: Found a similar posting here: LINQ vs. DataTable.Select - How can I get the same results?
They suggest using i4o which I am not familiar with, but it may be worth investigating (the asker of that question accepted i4o as the answer).