Entity Framework aliasing in join operation - c#

I am creating a query in Visual Studio for retrieving data from a SQL Server.
Can I, and if so how, use aliasing on variables in .Join()s?
I have something like:
var query =
context.tblOne
.Join(
context.tblTwo,
varOne => varOne.ParamFromVarOne,
varTwo => varTwo.ParamFromVarTwo,
(varOne, varTwo) => varOne)
Can I somehow access the "varOne" and "varTwo" objects and their parameters outside of the join? I need other parameters from varOne and two in my .Where() clause to filter the search result.
Is there perhaps another way to query for this?
I have 10 .Join()s and on those joins and after the .Where() I want to create a new JSON object.toList() using the
.Select(x => new {x.param1, x.param2, x.param3}) etc
A more abstract way of explaining what I want to do is something like:
.Where(x => x.Param1 <= compareVariable1 &&
x.Param2 >= compareVariable1 &&
y => y.Param1 == compareVariable2 &&
z => z.Param1 == compareVariable3)
In other words, a .Where() clause with multiple table-records from which I compare the column values to method parameters/arguments.
Can I perhaps concatenate the Joins and if so how do I go about this?

Related

LINQ: OrderByDescending by last value of multiple dates within the table

I am trying to do a OrderByDescending on my LINQ query. Currently I am doing OrderByDescending on ProcedureDate field.
Business Scenario:
A user can come in the application and add ChangeProcedureDates in application upto 3 times. So in database there are additional fields called ChangeProcedureDate1, ChangeProcedureDate2 and ChangeProcedureDate3.
What I am trying to accomplish:
I want to modify my LINQ query so it can check to see if in cases where ChangeProcedureDate1, ChangeProcedureDate2 and ChangeProcedureDate3 are NULL then OrderBy ProedureDate since there were no changes. If ProcedureDate, ChangeProcedureDate1 is filled and ChangeProcedureDate2 and ChangeProcedureDate3 are NULL then we need to OrderBy ChangeProcedureDate1. And same for ChangeProcedureDate2 and ChangeProcedureDate3. Basically I need to find the latest date entry among multiple DateTimeFields and do orderby on that.
Below is my LINQ query.
var unsortedItems = context.ReservationRequests
.Where(s => ((s.ReservationRequestStatusId.HasValue) &&
(s.ReservationRequestStatusId.Value == ReservationRequestStatusId)) &&
(Roles.Any(y => s.SubmitterGroupName == y) ||
s.CreatedBy == currentUserGuid))
.OrderByDescending(x => x.ProcedureDate ?? DateTime.MinValue);
I am having hard time trying to understand how can I do this in LINQ?
Try this:
.OrderByDescending(x => x.ChangeProcedureDate3 ?? x.ChangeProcedureDate2 ?? x.ChangeProcedureDate1 ?? x.ProcedureDate);
Or, change orders of properties as you need.

Where Clauses Causing Errors in LINQ

I am trying to return rows based on a search term that may include a space.
The code below is is generating the following error. I cannot figure out what I'm doing wrong, any suggestions?
Local sequence cannot be used in LINQ to SQL implementations of query
operators except the Contains operator.
var searchTerms = term.Split(' ').ToList();
var surveys = (from s in dc.BasicNeedsSurveys where s.Hidden ==
false orderby s.CreatedOn descending select s)
.Where(x => searchTerms.Any(y => y.Contains(x.FirstName))
|| searchTerms.Any(y => y.Contains(x.LastName))
|| searchTerms.Any(y => y.Contains(x.FEMANumber)));
according to the error message you are using linq to sql (or EF). linq to sql generate SQL query behind the scene, and you cant use a local var such as searchTerms inside an sql query. if i understand it correctly and dc.BasicNeedsSurveys is actually a data base entity (like in entity framework for example) your solution will be to first execute the sql query and then run the test if substring of search terms contains the search result. ToList is one function that can do that.
var searchTerms = term.Split(' ').ToList();
var surveys = (from s in dc.BasicNeedsSurveys where s.Hidden ==
false orderby s.CreatedOn descending select s)
.ToList()
.Where(x => searchTerms.Any(y => y.Contains(x.FirstName))
|| searchTerms.Any(y => y.Contains(x.LastName))
|| searchTerms.Any(y => y.Contains(x.FEMANumber)));
of course, there might be better ways to do that with better performance since here you are filtering the results only after you read all of them from the hard drive, but there is really not enough information in the question for that

Why Reverse() cannot be converted into SQL?

My application is running under ASP.NET 4.0, which uses BLToolkti as ORM tool.
I have some queryable expression:
var q = db.GetTable<T>()
.Where(tb=>tb.TeamId==MyTeamId && tb.Season==MySeasonId)
.OrderByDescending(tb=>tb.Id)
.Take(20)
.Reverse()
Attempt to convert q.ToList() causes the following error:
Sequence 'Table(TeamBudget).Where(tb => ((tb.TeamId ==
value(VfmElita.DataLogicLayer.Teams.Team+TeamBudget+<>c__DisplayClass78).teamId)
AndAlso (tb.Season ==
value(VfmElita.DataLogicLayer.Teams.Team+TeamBudget+<>c__DisplayClass78).season))).OrderByDescending(tb
=> Convert(tb.Id)).Take(20).Reverse()' cannot be converted to SQL.
If I remove ".Reverse()" from the queryable object everything works fine.
What is the reason why queryable object with .Reverse() cannot be converted into SQL? Is that BLToolkit limitation? Is there any solution workaround for that?
Thank you!
It's pretty clear what the other LINQ methods convert to (where, order by, top(20)), but what would Reverse() convert to? I can't think of an SQL statement I've seen that mimics that behavior, and when you're querying the database your LINQ statement must ultimately resolve to valid SQL.
This may not be what you're going for, but one option would be to execute the query first using ToList(), then apply Reverse():
var q = db.GetTable<T>()
.Where(tb => tb.TeamId == MyTeamId && tb.Season == MySeasonId)
.OrderByDescending(tb => tb.Id)
.Take(20)
.ToList()
.Reverse();
Alternatively, you could get the count and skip that many records first, although this could be inaccurate if the number of records change between calls. Plus it's two queries instead of just one.
var totalRecords = db.GetTable<T>()
.Count(tb => tb.TeamId == MyTeamId && tb.Season == MySeasonId);
var q = db.GetTable<T>()
.Where(tb => tb.TeamId == MyTeamId && tb.Season == MySeasonId)
.Order(tb => tb.Id)
.Skip(totalRecords)
.Take(20);

EF: LINQ - orderby using child collection with condition - ArgumentException

I'm running into troubles trying to sort IQueryable of my EF Entity.
My object structure is something like this:
Item
Item.CustomFieldValue [List<CustomFieldValue>]
Item.CustomFieldValue.DefinitionID
Item.CustomFieldValue.Value
and I'm working with
IQueryable<Item>
I'd need to sort it conditionally with values having desired definition id being sorted first something like this:
queryable = queryable
.OrderBy(p => p.CustomFieldValue
.Where(p2 => p2.DefinitionID == defId)
.Select(p3 => p3.Value)
.OrderBy(p4 => p4)
);
This however throws ArgumentException "DbSortClause expressions must have a type that is order comparable.".
I indeed understand what's the exception trying to say to me, I just can't figure out on how to change this so that valid query is generated.
Any help greatly appreciated
EDIT:
To bring some more light into the issue, I want to achieve something similar that this query does
SELECT * FROM ticketnumber t, customfieldvalue c
WHERE t.id like '%00000047%' and c.ticketnumberid = t.id
ORDER BY CASE
WHEN DefinitionId = 2125 THEN 1
ELSE 2
END, c.Value ASC
Alternatively, as time is starting to become a factor for me, is there a way I could append OrderBy in string form?
You probably want to use FirstOrDefault() at the end of the end of the first OrderBy so you won't be dealing with enumerables but with values.
queryable = queryable
.OrderBy(p => p.CustomFieldValue
.Where(p2 => p2.DefinitionID == defId)
.Select(p3 => p3.Value)
.OrderBy(p4 => p4)
.FirstOrDefault()
);
Modification of Joanvo's answer did the trick, this is the working code [I've removed the inner OrderBy]
queryable = queryable.OrderBy(p => p.CustomFieldValue.Where(p2 => p2.DefinitionID == defId).Select(p3 => p3.Value).FirstOrDefault());

Convert string to long type and use in a linq query within asp.net MVC

Is it possible within Linq in C#, to convert a string field in a database, to a long type - and use it in the query?
Here, tme is a unix time (long) - but the field in the database, targetdate - is a string.
I've tried:
var qbt = db.Calls
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
However I get the message: LINQ to Entities does not recognize the method 'Int64 Parse(System.String)' method, and this method cannot be translated into a store expression.
I know you can convert before the linq query, but is there any way of using it WITHIN the linq query?
Thanks for any help,
Mark
try
var qbt = db.Calls.ToList()
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
if you have many records you can limit them by team first and then call ToList like below
var qbt = db.Calls.Where(x => x.team == id).ToList()
.Where(i=>long.Parse(i.targetdate) <= tme);
Or You can use AsEnumerable
var qbt = db.Calls.AsEnumerable()
.Where(x => x.team == id && long.Parse(x.targetdate) <= tme);
This is to do with the way the Linq is translated into the backing query language, it might be easier to do a string comparison in this case, using tme.ToString(). If you pull the full collection down first, you could query like this but that means what it says: pulling down the full unfiltered (or at least less filtered) set.
You have to either change the database table to not store a string (you could create a computed column that converts it to a long or create a view if you cannot modify the existing table) or compare the value as string. The reason is that Entity Framework LINQ provider does not understand long.Parse and there is no method in SqlFunctions class for this purpose.
var stringTme = tme.ToString(CultureInfo.InvariantCulture);
var qbt = db.Calls
.Where(x => x.team == id && ((x.targetdate.Length < stringTme.Length)
|| (x.targetdate.Length == stringTme.Length && x.targetdate <= stringTme)));
You have to either change the database table to not store a string or compare the value as string. The reason is that Entity Framework LINQ provider does not understand long.Parse and there is no method in SqlFunctions class for this purpose.please use long.Parse()

Categories

Resources