im trying to remove a few items from a query results using linqCore but its not removing them
code& results
IQueryable<int> postOn = //Results=9(Id)
_context.QuettaOffers.Where(d => d.SiteUserId == LoguserId).Select(s => s.QuettaReqId);
//Get all request that relevant to user without the one he already post on
IOrderedEnumerable<QuettaReq> listOfR = //Results= 9,11 (Id) should be ..11(Id)
//IQueryable<QuettaReq> listOfR
_context.Quetta.Include(q => q.Category)
.Where(d => d.OfferDate > DateTime.Now && d.CatId == suplayerCat)
.ToList()
//.ToList()
.SkipWhile(a => a.Id.Equals(postOn))
.OrderBy(x => x.Id);
// .TakeWhile(a => a.Id != postOn);
There are several issues with your code.
First, SkipWhile / TakeWhile are useless for unordered sequences, which are normally the result of EF queries except they include explicit OrderBy. The standard and more appropriate method for filtering is Where.
Second, a.Id.Equals(postOn) resolves to object.Equals, and since a.Id is int and postOn is IQueryable<int>, it always evaluates to false.
What you really need is additional Where condition based on !Contains. It could be && to the current Where or just separate Where (these constructs are treated one and the same way):
_context.Quetta.Include(q => q.Category)
.Where(d => d.OfferDate > DateTime.Now && d.CatId == suplayerCat)
.Where(q => !postOn.Contains(q.Id))
The additional benefit would be that the filtering will happen server side.
SkipWhile will only skip items in the beginning of the IEnumerable<T>. Once that condition isn't met it will happily take the rest of the elements. Other elements that later match it down the road won't be skipped.
instead of SkipWhile you can use Except
var result = QueryResult.Except(a => a.Id.Equals(Id here));
Related
I want to search using soundex() with each words of a sentence.
My C# code is:
all_data = db.SearchEntities.Where(
s => (s.EventTitlePrimaryLang
.Split(' ')
.ToArray()
.Any(d => SqlFunctions.SoundCode(d.ToString()) ==
SqlFunctions.SoundCode(srQuery.ToString())
))
)
//.AsEnumerable()
//.AsQueryable()
.ToList();
Getting this error
LINQ to Entities does not recognize the method 'System.String[]
ToArrayString'
method, and this method cannot be translated into a store expression.
Your issue is that you are attempting to filter on the split results of a property in your query. Everything in the .Where() clause off the DbSet called SearchEntities will need to be evaluated as SQL.
The error message is telling you that EF can't convert x.MyProperty.Split() into SQL.
The only alternative, which might not be desirable in this case is to have a more general filter, then perform the complex filtering in you materialised results.
db.SearchEntities.Where(s => Something general to narrow down your results)
.AsEnumerable() // materialise your results
.Where(s => s.EventTitlePrimaryLang
.Split(' ')
.Any(d => something specific with your d and sQuery))
.ToArray();
all_data = db.SearchEntities.Where(x => !string.IsNullOrWhiteSpace(x.EventTitlePrimaryLang))
.ToList();
var filteredData = all_data.Where(s => (s.EventTitlePrimaryLang.Split(' ')
.Any(d => SqlFunctions.SoundCode(d)) == SqlFunctions.SoundCode(srQuery)))
.ToList();
OR
all_data = db.SearchEntities.Where(x => !string.IsNullOrWhiteSpace(x.EventTitlePrimaryLang))
.AsEnumerable()
.Where(s => (s.EventTitlePrimaryLang.Split(' ')
.Any(d => SqlFunctions.SoundCode(d)) == SqlFunctions.SoundCode(srQuery)))
.ToList();
As Pointed out by reckface in another answer.
OR
As another alternative to the above which may or may not work, you could opt to build the query using for loops.
var results = db.SearchEntities.Where(x => !string.IsNullOrWhiteSpace(x.EventTitlePrimaryLang))
.AsQueryable();
foreach(var r in results) {
var langSplit = s.EventTitlePrimaryLang.Split(' ');
foreach(var val in langSplit) {
results = from a in results
where SqlFunctions.SoundCode(val) == SqlFunctions.SoundCode(srQuery)
select a;
}
}
return results.ToList();
The above would then filter your results bit by bit.
EDIT:
Removed The redundant .ToString() calls
EDIT 2:
Edited the code example to better help fix the problem and Identify what is wrong.
The problem is that Entity Framework cannot convert .Split(' ') into valid SQL Code. As a work around, you will need to retrieve the data first, then filter that data using LINQ
EDIT 3:
Added possibly another way to solve the issue by using .AsQueryable() to filter down the results. Thus you don't need to query the database for a large dataset and filter the results, you could get the filtered results from the db directly, assuming it dosen't build the split into the database query. I have not tested it.
I've a structure based of list containing other list. I need to filter the list based on the value of a property based in the deepest part of the list.
Right now I'm doing this:
queryable = queryable
.Include(x => x.Carriers)
.ThenInclude(c => c.CarrierActions)
.ThenInclude(ca => ca.Action)
.ThenInclude(ac => ac.ActionFacts);
queryable = queryable
.Where(x => x.Carriers.Any(
carriers => carriers.CarrierActions.Any(
carrieractions =>
carrieractions.Action.ActionTypeId ==
ActionTypeEnum.DosemeterCalculateDeepDose)));
I join the needed tables, then I filter them based on the ActionTypeId based 3 levels below the top list.
First off all, is it possible to do this in 1 step ( include the filtering with the joins ), second of all, the second part is not working as my list gets empty, but I'm certain that actions with that type get values.
Using .NET Core 2.0.3 btw!
To answer your first part, you can do this
queryable = queryable
.Include(x => x.Carriers)
.ThenInclude(c => c.CarrierActions)
.ThenInclude(ca => ca.Action)
.ThenInclude(ac => ac.ActionFacts)
.Where(x => x.Carriers.Any(
carriers => carriers.CarrierActions.Any(
carrieractions =>
carrieractions.Action.ActionTypeId ==
ActionTypeEnum.DosemeterCalculateDeepDose)))
To your second part, it should be working, id check your data, as this is pretty straight forward
I have this code but I'm not sure which of the 2 options below would be more efficient. Could anyone let me know which is more efficient and why?
var list1 = await context.Data.Where(i => i.Market == "nasdaq").DistinctBy(i => i.Symbol).Select(i => i.Symbol).ToListAsync();
var list2 = await context.Data.Where(i => i.Market == "nasdaq").Select(i => i.Symbol).DistinctBy(i => i).ToListAsync();
Note: I use the MoreLinq Library
Since MoreLinq library does not provide DistinctBy on IQueryable<T>, only on IEnumerable<T>, the part of your first query after Where completes in memory. Hence, the entire object gets transferred, which is suboptimal.
The second query takes only Symbol, so it is slightly better. However, duplicate symbols are still transferred into memory, so there's room for optimization.
You can improve on it by observing that DistinctBy(i => i) is the same as Distinct():
var list2 = await context.Data
.Where(i => i.Market == "nasdaq")
.Select(i => i.Symbol)
.Distinct()
.ToListAsync();
Now everything is done on the RDBMS side, including elimination of duplicates.
** Found the actual problem that was happening...due to records it wasn't obvious at first this was the case LINQ Query returns multiple copies of first result **
As the title says, the "pgnIDs.Contains(item.pgn)" part below is only selecting based on the first element of the hashset. I'd expect it to select a record if "item.pgn" is ANY of the values in pgnIDs.
HashSet<string> pgnIDs = new HashSet<string> { "EFFA", "EFFF", "FEE8", "FEE6", "FEF3", "FFF8", "FFFF" };
//...
var innerQ = (db1.can_raw_data_grainquality_2017
.Where(item => item.ref_id == q.ref_id &&
pgnIDs.Contains(item.pgn))
.OrderBy(item => item.ts_sec)
.ThenBy(item => item.ts_usec)
.Select(item => item)).ToList();
** update **
I tried with a straight "OR" for two of the values in the hashset and LINQ still only selected based on one of them. Is this behavior expected? Either one of the values below will work alone (in that records will be found).
var innerQ = (db1.can_raw_data_grainquality_2017
.Where(item => item.ref_id == 29225 &&
(item.pgn == "FFF8" || item.pgn == "EFFA"))
.OrderBy(item => item.ts_sec)
.ThenBy(item => item.ts_usec)
.Select(item => item.pgn)).ToList();
Per Ivan's comment (thanks!) I got the raw SQL query out and even tried it in SSMS. It did in fact work as expected in SSMS/raw SQL???
SELECT
[Extent1].[pgn] AS [pgn]
FROM (SELECT
[can_raw_data_grainquality_2017].[ts_sec] AS [ts_sec],
[can_raw_data_grainquality_2017].[ts_usec] AS [ts_usec],
[can_raw_data_grainquality_2017].[channel] AS [channel],
[can_raw_data_grainquality_2017].[mid] AS [mid],
[can_raw_data_grainquality_2017].[pgn] AS [pgn],
[can_raw_data_grainquality_2017].[sa] AS [sa],
[can_raw_data_grainquality_2017].[dlc] AS [dlc],
[can_raw_data_grainquality_2017].[d0] AS [d0],
[can_raw_data_grainquality_2017].[d1] AS [d1],
[can_raw_data_grainquality_2017].[d2] AS [d2],
[can_raw_data_grainquality_2017].[d3] AS [d3],
[can_raw_data_grainquality_2017].[d4] AS [d4],
[can_raw_data_grainquality_2017].[d5] AS [d5],
[can_raw_data_grainquality_2017].[d6] AS [d6],
[can_raw_data_grainquality_2017].[d7] AS [d7],
[can_raw_data_grainquality_2017].[ref_id] AS [ref_id]
FROM [dbo].[can_raw_data_grainquality_2017] AS [can_raw_data_grainquality_2017]) AS [Extent1]
WHERE (29225 = [Extent1].[ref_id]) AND ([Extent1].[pgn] IN (N'FFF8',N'EFFA'))
ORDER BY [Extent1].[ts_sec] ASC, [Extent1].[ts_usec]
I'm trying to find all customer codes where the customer has a status of "A" and whose code does not contain any letter using LINQ query.
var activeCustomers = Customers.Where(x => x.Status == "A" && x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code);
When I run this query in LinqPad I get the following error:
You'll need to do this as a two part query. First, you could get all the users who's status is "A":
var activeCustomers = Customers.Where(x => x.Status == "A").ToList();
After you've got those in-memory, you can create an additional filter for char.IsDigit:
var codes = activeCustomers.Where(x => x.Code.Any(n => !char.IsLetter(n)))
.Select(x => x.Code)
.ToArray();
As commenters have stated, IsLetter() cannot be translated to SQL. However, you could do the following, which will first retrieve all items with Status "A" from the database, then will apply your criteria after retrieval:
var activeCustomers = Customers.Where(x => x.Status == "A").AsEnumerable().Where(x => x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code);
You'll have to determine if it's acceptable (from a performance perspective) to retrieve all customers with "A" and then process.
The AsEnumerable() transitions your LINQ query to working not with IQueryable (which works with SQL) but with IEnumerable, which is used for plain LINQ to objects.
Since it is LINQ 2 SQL, there is no natural way to translate char.IsLetter to something SQL can understand. You can hydrate a query that retrieves your potential candidates and then apply an addition in-memory filter. This also solves the issue where LINQ 2 SQL has a preference for a string and you are dealing with chars
var activeCustomers = Customers.Where(x => x.Status == "A").ToList();
var filteredCustomers = activeCustomers.Where(x =>
x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code).ToList();
There are two performance hits here. First, you're retrieving all potential records, which isn't too desirable. Second, in your above code you were only interested in an enumerable collection of codes, which means our query is including far more data than we originally wanted.
You could tighten up the query by only returning back to columns necessary to apply your filtering:
var activeCustomers = Customers.Where(x => x.Status == "A")
Select(x => new Customer{ Status = x.Status, Code = x.Code }).ToList();
You still return more sets than you need, but your query includes fewer columns.