LINQ: Help with linq query and contains for an IEnumerable<string>? - c#

Can anyone help?
I have a linq query which is embedded inside a extension method, it was working as v.RentalStatus was a String. I am now using a Group on my original query (the query is quite complex so i won't put it here).
The importante thing is that v.RentalStatus = IEnumerable hence it can contain things like
A (meaning active)
R (meaning rented)
U (unavailable)
etc - many more
I create a list of what i would like to get back and store this in statusStringList, so for example lets say the list contains A and R
This is my code from before when the v.RentalStatus was just a string, can anyone tell me how i can modify this to work.
var statusStringList = rentalStatus.ToList().ConvertAll<string>(st => st.GetStringValue());
return from v in qry
where statusStringList.Contains(v.RentalStatus)
select v;
If it helps this is part of my query which returns the RentalStatus - its part of a group query but the RentalStatus is not in the group by
RentalStatus= g1.Select( j => j.IdRentalStatus).Distinct(),
g1 is my group by, so if you imagine there are 10 "A", 5 "U" .. then it would return an ienumerable of A and U ... as i am using Distinct. Not 10 As and 5 Us
I hope i have explained it well, please tell me if i haven't
I would appreciate any help from anyone ..
thanks
EDIT
This is my extension signature but not that it matters.
public static IQueryable<Rentals> WithStatus(this IQueryable<Rentals> qry, IList<Contants.Statuses> rentalStatus)
{
EDIT
As mentioned previously when v.RentalStatus was a string it was working but now its IEnumerable - hence a collection.. and it errors with this
Argument '1': cannot convert from 'System.Collections.Generic.IEnumerable<string>' to 'string'

If RentalStatus has changed from a string to a IEnumerable<string> then your comparing 2 list... I think this should work:
return from v in qry
where v.RentalStatus.Any(status => statusStringList.Contains(status))
select v;
This should give you any rentals that have a status that is in the list you are providing
Edit:
Yeah I would spend some time learn lambda expressions. Seems like they are being used more and more and with good reason. Here are a few links for tutorials:
An Extensive Examination of LINQ: Lambda Expressions and Anonymous Types
.NET Lambda Expressions – Resources
"WHERE" RentalStatus = Containing any
of itself - arrgghh -
Is that true? I thought the list of rentalStatuses is a parameter in your method. I was thinking your query basically would allow me to get all the rentals that have a status that matches any of the list that I specified. One list lives on your Rental object and the other is the one I pass in...
As to why the order in mine worked. I have some questions:
Are you using this to query a database? Are you able to look at the tsql it generates?
If so, I would look at the tsql and see what the difference is. I would have to check myself. I got lucky I guess.

You could try something like this:
where statusStringList.Any(x => v.RentalStatus.Contains(x))

I am not sure but I think that for a Contains to work in Linq to SQL it must be an array of strings (or ints or ...) and not any IEnumerable. I would thus try:
var statusStringArray = rentalStatus.ToList().ConvertAll<string>(st => st.GetStringValue()).ToArray();
return from v in qry
where statusStringArray.Contains(v.RentalStatus)
select v;
There might be other issues though, I did not look that much.

Try this:
return from v in qry
where rentalStatus.Any( r => r.IdRentalStatus == v.RentalStatus)
select v;

Related

LINQ pull records from a database where string list is from a model

I have a database of strings that contain IDs. I need to pass that list into a LINQ query so I can pull the correct records.
model.SelectedDealers = db.dealers.Any(a => a.sdealer_name.Contains(UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber)));
SelectedDealers is of type dealers
ViewReferenceNumber should be a list of strings which should match sdealer_name
So essentially I am trying to find all of the dealers whos sdealer_name matches the list of sdealer_names I have in my UserToEdit.UserViewAccesses
I've tried moving parts around and switching them in different spots and can't seem to figure this out.
Any() is just a boolean indicating if there are any results. It doesn't actually return the results.
If I understand what you are after correctly, then this might work:
var dealerNames = UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber).ToList();
model.SelectedDealers = db.dealers.Where(a => dealerNames.Contains(a.sdealer_name));
So essentially I am trying to find all of the dealers whos
sdealer_name matches the list of sdealer_names I have in my
UserToEdit.UserViewAccesses
var dealersthatmatched = (from d in UserToEdit.UserViewAccesses.sdealer_names
where d == sdealer_name
select d).ToList()
Wish I could have made a comment instead, but as I don't have enough rep I can't. I wish I understood the requirement better, but you seem ready and able to try stuff so perhaps you find this useful.

How to use Orderby Clause with IEnumerable

I have written following code:
IEnumerable<Models.bookings> search = new List<bookings>();
search = new available_slotsRepositories().GetAvailableSlot(param1,param2);
var data = from s in search.AsEnumerable().
OrderByDescending(c => c.BookingDate)
select s;
i have also tried this and it does not work:
search.OrderByDescending(c => c.BookingDate);
Third line gives me following error:
Expression cannot contain lambda expressions
Any one guide me how can i fix this issue?
Any help would be appreciated.
Thank you!
why r u using new List()??
follow the below pattern
IEnumerable<Step> steps = allsteps.Where(step => step.X <= Y);
steps = steps.OrderBy(step => step.X);
NOTE:
IEnumerable makes no guarantees about ordering, but the implementations that use IEnumerable may or may not guarantee ordering.
For instance, if you enumerate List, order is guaranteed, but if you enumerate HashSet no such guarantee is provided, yet both will be enumerated using the IEnumerable interface
Perhaps you are looking for the IOrderedEnumerable interface? It is returned by extensions methods like OrderBy() and allow for subsequent sorting with ThenBy().
Have you tried
var data = (from s in search
OrderByDescending(c => c.BookingDate)
select s).ToList();
That will make a List which is IEnumerable.
I'm not sure why you need "new" if as you say GetAvailableSlot returns an IEnumerable. What I think your code should look like assuming GetAvailableSlot returns IEnumerable is this:
var data = available_slotsRepositories().GetAvailableSlot(param1,param2).ToList().OrderByDescending(c => c.BookingDate);
All you're doing to your recordset is ordering the results there is no need to have multiple variables declared. If this still doesn't work then we need to see more of the code in order to see what the problem is...

LINQ to SQL, condition on foreign entities

In SQL, it'd be done as such:
SELECT * FROM Student
WHERE SchoolId IN
(SELECT id FROM School WHERE Name LIKE '%elementary%')
How do I implement this with LINQ? I've tried the following:
var list = context.Students.Where(x => context.Schools.Where(r => r.Name.Contains("elementary").Select(r => r.Id).Contains(x.SchoolId))
but it's not giving me what I want, unfortunately...
I know it's possible to retrieve all the Ids from the School table first, but I think it'd take a heavy toll on the performance. Preferably I'd like LINQ to SQL to handle everything; I can't do this using vanilla SQL because I need stuff to be dynamic and currently LINQ is the best solution for me.
The code above is all for illustration purposes; what I'm doing is a tad different (but more or less the same). I really do need some help on this; if you need any more information just feel free to ask.
EDIT: My bad, I missed out a field. It works, but the results didn't show up because I was missing that field... So sorry...
Try this:
var result = from st in context.Student
from sc in context.Schools
where sc.Name.Contains("elementary") && sc.SchoolId == st.SchoolId
select st;
I am a bit hazy on the syntax, pardon me. But this should point you to the right direction.
Something like this should work. The first use of Contains is on a string object to see if the string contains the substring "elementary". The second use of Contains is on a list and checks to see if the first result list contains SchoolId.
var sublist = from s in context.Schools
where s.Name.Contains("elementary")
select id;
var list = from s in context.Students
where sublist.Contains(s.SchoolId)
select s;

Convert IQueryable<T> or LINQ query to unique string

I have some LINQ query (or IQueryable<T> object based on LINQ query) and want to get some unique string based on this query.
I have, for example:
var someValue = 10;
var query = (from i in db.Customers
where i.Id == someValue
select i).AsQueryable();
I should get something like this:
"from i in db.Customers where i.Id == 10"
I am trying to use Expression object and play with it but I can not get generic approach to get string with exact parameters values.
E.g.:
public string GetKey<T>(IQueryable<T> query)
{
...
return unique_string;
}
Note that different parameters values for the same LINQ query should provide different strings.
Thanks in advance.
I strongly suspect that this is simply not going to work. Aside from anything else, if you have to use AsQueryable (i.e. if your original query is over IEnumerable<T> then the compiler will have used delegates instead of expression trees to start with.
If it's a pure IQuerable<T> all the way, you could try using query.Expression.ToString(), but frankly it's not something I'd want to rely on.
Solved this issue with Expression Tree Serialization with some improvements for getting exact values of passed parameters. It provides a big but unique XML file based on IQueryable objects.

How to use LINQ to SQL to create ranked search results?

I am looking for a way to use l2s to return ranked result based on keywords.
I would like to take a keyword and be able to search the table for that keyword using .contains(). The trick that I haven't been able to figure out is how to get a count of how many times that keyqord appears, and then .OrderByDescending() based on that count.
So if i had some thing like:
string keyword = "SomeKeyword";
IQueryable<Article> searchResults = from a in GenesisRepository.Article
where a.Body.Contains(keyword)
select a;
What is the best way to order searchResults based on the number of times keyword appears in a.Body?
Thanks for any help.
try inserting order by a.Body.Split(' ').Count(w=>w == keyword). That should allow you to see that the concept works. However, I STRONGLY recommend that the final version include this as part of the select projection, possibly using a key-value pair, and order by the property name:
string keyword = "SomeKeyword";
//EDIT: restructured query to force the ordering to be done on the projection,
//not the source.
IQueryable<Article> searchResults = (from a in GenesisRepository.Article
where a.Body.Contains(keyword)
select new KeyValuePair<int, Article>(
a.Body.Split(' ').Count(w=>w == keyword), a))
.OrderBy(kvp=>kvp.Key);
The reason is performance; the Split().Count() method chain is linear-complexity, and will be evaluated for every comparison of two values, making the overall sort N^2logN complexity (slow).
EDIT: Also, understand that a.Body.Contains(keyword) will not search by whole words, and so will return articles that contain "SomeKeywordLongerThanSearch" and "ThisIsSomeKeyword" as well as "SomeKeyword". You can avoid this with a Regex match on the pattern "\bSomeKeyword\b", which will only match instances of SomeKeyword with a word boundary immediately before and after.
This is a little hack I came up with, pretty simple but definitely not a "best practices" one.
IQueryable<Article> searchResults = from a in GenesisRepository.Article
where a.Body.Contains(keyword)
orderby a.Body.Split(new string[] { keyword }, StringSplitOptions.RemoveEmptyEntries).Count() descending
select a;
Maybe this will work...
IQueryable<Article> searchResults = from a in GenesisRepository.Article
where a.Body.Contains(keyword)
select a;
searchResults.OrderByDescending(s => Regex.Matches(a.Body, keyword).Count);

Categories