I can't read complicated lambda expression and only the super basic lambda expression only I know I am just starting to study lambda.
As my title above how to convert this lambda into linq?
var train = db.Certificates
.Join(db.TrainingSchedules, a => a.CertificateId, b => b.CertificateId, (a, b) => new { a, b })
.Where(x => x.a.Year.Value.Year == year && x.a.TrainingTypeId.Value == trainingTypeId && x.a.IsApproved.Value && x.b.EndDate >= DateTime.Now)
.Select(z => z.a).Distinct().Where(q => !db.Registrations.Where(s => s.EmployeeId == empId).Select(t => t.Certificate).Any(u => u.CertificateId == q.CertificateId));
Can someone explain to me why it has a different variables?. Like x , q , z , b
?
As my title above how to convert this lambda into linq?
Have you every worked in Linq
to know how does it looks like ?
If the above specified code is not Linq
, then what is Linq
, Lambda
is an integral part of fluent
representation of the Linq
, since most of the APIs would need a Func delegate
, that's where Lambda
comes in.
Now regarding
x , q , z , b
, what do they represent ?
The Linq APIs are nothing but extension methods for IEnumerable<T>
, like List<T>
, Dictionary<TK,TV>
, whether we write the fluent' or the
Sql syntax these variables represent, each and every element in the collection, which is processed as part of logic provided by the
Func Delegate , you can certainly use and should use more credible variable to represent the exact thing, similar to other parts of code where
int x, float y, DateTime z` is a bad way to code
Regarding the statement posted above consider following changes:
a,b
as cert,ts
, which refers to a Certificate
and Training Schedule
classes respectively new { a, b }
, create a class
like CerificateTrainingSchedule
that has all the elements of the Certificate
and Training Schedule
class respectively, it would be easier to work as you move forward x
as cts
, to represent combined CerificateTrainingSchedule
If its easy to read then separate Where
clause in multiple chains, like:
.Where(cts => cts.a.Year.Value.Year == year) .Where(cts => cts.a.TrainingTypeId.Value == trainingTypeId) .Where(cts => cts.a.IsApproved.Value) .Where(cts => cts.b.EndDate >= DateTime.Now)
a,b,c,d
. Also calls can be chained for clear understanding of the logic Edit - // Modified Linq Query
// Joined / Merged version of Certificate and Training Schedule, add more fields as required, current one is based on certain assumptions of the fields / properties in the Certificate & TrainingSchedule classes respectively
public class CertificateTrainingSchedule
{
public int Year {get; set;} // Certificate Class Property
public int TrainingTypeId {get; set;} // Certificate Class Property
public bool IsApproved {get; set;} // Certificate Class Property
public DateTime EndDate {get; set;} // TrainingSchedule Class Property
}
var train = db.Certificates
.Join(db.TrainingSchedules, cert => cert.CertificateId, ts => ts.CertificateId, (cert, ts) => new CertificateTrainingSchedule{ Year = cert.Year, TrainingTypeId = cert.TrainingTypeId, IsApproved = cert.IsApproved,EndDate = ts.EndDate})
.Where(cts => cts.Year == year)
.Where(cts => cts.TrainingTypeId == trainingTypeId)
.Where(cts => cts.IsApproved)
.Where(cts => cts.EndDate >= DateTime.Now)
.Select(cts => new {cts.Year,cts.TrainingTypeId,cts.IsApproved})
.Distinct() // Allowing anonymous type to avoid IEqualityComparer<Certificate>
.Where(certMain => !db.Registrations.Where(s => s.EmployeeId == empId)
.Select(cert => new Certificate{Year = cert.Year,TrainingTypeId = cert.TrainingTypeId,IsApproved = cert.IsApproved})
.Any(cert => cert.CertificateId == certMain.CertificateId))
I assume that by your question, you mean you want a query expression that is equivalent to calling the LINQ methods explicitly. Without a good Minimal, Complete, and Verifiable code example , it's impossible to know for sure what a correct example would be. However, the following is I believe what you're looking for:
var train =
from q in
(from x in
(from a in db.Certificates
join b in db.TrainingSchedules on a.CertificateId equals b.CertificateId
select new { a, b })
where x.a.Year.Value.Year == year && x.a.TrainingTypeId == trainingTypeId &&
x.a.IsApproved.Value && x.b.EndDate >= DateTime.Now
select x.a).Distinct()
where !(from s in db.Registrations where s.EmployeeId == empId select s.Certificate)
.Any(u => u.CertificateId == q.CertificateId)
select q;
Note that not all of the LINQ methods have a C# query expression language equivalent. In particular, there's no equivalent for Distinct()
or Any()
, so these are still written out explicitly.
Can someone explain to me why it has a different variables?. Like x , q , z , b?
Each lambda expression has the input on the left side of the =>
and the result expression on the right. The variables you're referring to are the inputs. These are commonly written using single letters when writing lambda expressions, because the a lambda expression is so short, the meaning can be clear without a longer variable name. For that matter, independent lambda expressions could even use the same variable name.
Note that in the query expression syntax, not all of the variables "made it". In particular, we lost z
and t
because those variables were superfluous.
In an expression this long, it's possible you might find longer variable names helpful. But it's a trade-off. The query expression language is meant to provide a compact way to represent queries on data sources. Longer variable names could make it harder to understand the query itself, even as it potentially makes it easier to understand the intent of each individual part of the expression. It's very much a matter of personal preference.
I can't read complicated lambda expression and only the super basic lambda expression only I know I am just starting to study lambda.
Try reading this:
var train = db.Certificates
.Where(c => c.Year.Value.Year == year &&
c.TrainingTypeId.Value == trainingTypeId &&
c.IsApproved.Value &&
c.TrainingSchedules.Any(ts => ts.EndDate >= DateTime.Now) &&
!c.Registrations.Any(r => r.EmployeeId == empId));
If you can, then you are just fine.
Note that this is not an exact translation of the sample query, but is functionally equivalent (should produce the same result). The sample query is a good example of badly written query - variable naming, unnecessary multiplicative Join
which requires then a Distinct
operator (while GroupJoin
would do the same w/o the need of Distinct
), inconsistent handling of two similar detail criteria ( Join
for TrainingSchedules
and Any
for Registrations
), overcomplicated criteria for Registrations
part etc.
Shortly, don't write such queries. Concentrate on the desired result from the query and use the most logical constructs to express it. Avoid manual joins when you have navigation properties. If you don't have navigation properties, then add them to the model - it's easy one time action which helps a lot when writing queries. For instance, in my translation I assume you have something like this:
class Certificate
{
// Other properties ...
public ICollection<TrainingSchedule> TrainingSchedules { get; set; }
public ICollection<Registration> Registrations { get; set; }
}
class TrainingSchedule
{
// Other properties ...
public Certificate Certificate { get; set; }
}
class Registration
{
// Other properties ...
public Certificate Certificate { get; set; }
}
UPDATE: Here is the same using the query syntax:
var train =
from c in db.Certificates
where c.Year.Value.Year == year &&
c.TrainingTypeId.Value == trainingTypeId &&
c.IsApproved.Value &&
c.TrainingSchedules.Any(ts => ts.EndDate >= DateTime.Now) &&
!c.Registrations.Any(r => r.EmployeeId == empId)
select c;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.