How to Convert Linq to Lambda Expression - c#

var getr = (from d in _context.DR
join r in _context.R on d.RID equals r.RID
where HID == r.HID && cI >= d.DRD && cO < d.DRD
group d by new {d.RID, d.RGID} into g
select g);
How to convert Linq to lambda? This is what I got:
var getr = _context.DR.Join(_context.R, x => x.RID, y => y.RID, (x, y) => new { R= x, DR= y}).Where(z => z.DR.RID== y.RID);
Are there any pros and cons of using either one?

In terms of performance : there is no performance difference whatsoever between two.
Which one should use is mostly personal preference, but its important to bear in mind that there are situation where one will be better suited the other.
int[] ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// using Query expression
var evensQuery = from i in ints where isEven(i) select i;
// using Lambda expression
var evensLambda = ints.Where(isEven);
There so many function that available with lambda ie. single(), First(), Take(), Skip()..
Although you can mix and match the two by calling the Lambda-only methods at the end of the query:
// mix and match query and Lambda syntax
//Example ver :1
var query = (from person in people
join pet in pets on person equals pet.Owner
select new { OwnerName = person.Name, Pet = pet.Name }).Skip(1).Take(2);
or, for better readability :
//Example ver :2
var query = from person in people
join pet in pets on person equals pet.Owner
select new { OwnerName = person.Name, Pet = pet.Name };
var result = query.Skip(1).Take(2);
Both example version return the same output without performance differences because of delayed(or Deferred ) execution, that means query is not executing at the point of declaration, but it will execute when try to iterate through the result variable.
BUT, if you don’t want delayed execution, or need to use one of the aggregate functions such as Average() or Sum(), for example, you should be aware of the possibility of the underlying sequence being modified between the assignments to query and result. In this case,I’d argue it’s best to use Lambda expressions to start with or add the Lambda-only methods to the query expression.

Related

Linq to SQL left outer join using Lambda syntax and joining on 2 columns (composite join key)

I am trying to make an Inner Join on 2 columns with Linq to SQL as a Lambda expression. The normal query would look like this.
SELECT * FROM participants
LEFT OUTER JOIN prereg_participants ON prereg_participants.barcode = participants.barcode
AND participants.event_id = prereg_participants.event_id
WHERE (participants.event_id = 123)
I am succeeding in making a Left Outer Join on one column with the following code.
var dnrs = context.participants.GroupJoin(
context.prereg_participants,
x => x.barcode,
y => y.barcode,
(x, y) => new { deelnr = x, vi = y })
.SelectMany(
x => x.vi.DefaultIfEmpty(),
(x, y) => new { deelnr = x, vi = y })
.Where(x => x.deelnr.deelnr.event_id == 123)
.ToList();
The problem is that with the above Lambda I get too many results because it is missing the AND participants.event_id = prereg_participants.event_id part. But whatever I try i'm not getting the correct amount of participants.
I looked at the following existing questions, but none solved my problem in writing the correct lambda. And most of the solutions are nog in lambda-format or not a Left outer join on multiple columns.
How to do joins in LINQ on multiple fields in single join
LINQ to SQL - Left Outer Join with multiple join conditions
Group By using more than two columns by Lambda expression
And most of these from this Google search
Query:
var petOwners =
from person in People
join pet in Pets
on new
{
person.Id,
person.Age,
}
equals new
{
pet.Id,
Age = pet.Age * 2, // owner is twice age of pet
}
into pets
from pet in pets.DefaultIfEmpty()
select new PetOwner
{
Person = person,
Pet = pet,
};
Lambda:
var petOwners = People.GroupJoin(
Pets,
person => new { person.Id, person.Age },
pet => new { pet.Id, Age = pet.Age * 2 },
(person, pet) => new
{
Person = person,
Pets = pet,
}).SelectMany(
pet => pet.Pets.DefaultIfEmpty(),
(people, pet) => new
{
people.Person,
Pet = pet,
});
See code, or clone my git repo, and play!
I was able to get this LEFT OUTER JOIN on the composite foreign key pair barcode, event_id working in both Linq2Sql, and Entity Framework, converting to lambda syntax as per this query syntax example.
This works by creating an anonymous projection which is used in match of the left and right hand sides of the join condition:
var dnrs = context.participants.GroupJoin(
context.prereg_participants,
x => new { JoinCol1 = x.barcode, JoinCol2 = x.event_id }, // Left table join key
y => new { JoinCol1 = y.barcode, JoinCol2 = y.event_id }, // Right table join key
...
Notes
This approach relies on the automagic equality given to identical anonymous classes, viz:
Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashCode methods of the properties, two instances of the same anonymous type are equal only if all their properties are equal.
So for the two projections for the join keys need to be of the same type in order to be equal, the compiler needs to see them as the same anonymous class behind the scenes, i.e.:
The number of joined columns must be the same in both anonymous projections
The field types must be of the same type compatable
If the field names differ, then you will need to alias them (I've used JoinColx)
I've put a sample app up on GitHub here.
Sadly, there's no support yet for value tuples in expression trees, so you'll need to stick to anonymous types in the projections.
If it is a LEFT OUTER JOIN, where the left entity can have zero or maximally one connection with right entity, you can use:
// Let's have enumerables "left" and "right"
// and we want to join both full entities with nulls if there's none on the right.
left.GroupJoin(
right,
l => l.LeftKey,
r => r.RightKey,
(l, r) => new { Left = l, Right = r.FirstOrDefault() });
If you want to join left with just one attribute of right:
// Let's have enumerables "left" and "right"
// and we want to join right's attribute RightId and to set 0 for those having no Id.
left.GroupJoin(
right,
l => l.LeftKey,
r => r.RightKey,
(l, r) => new { Left = l, RightId = r.FirstOrDefault()?.RightId ?? 0 });
You can do this by making use of anonymous types.
Example:
var result = from a in context.participants
join b context.prereg_participants on new { X = a.barcode, Y = a.event_id } equals new { X = b.barcode, Y = b.event_id } into A
from b in A.DefaultIfEmpty()
where a.event_id = 123

How to skip repeated ids from table and select remains using linq

In a table i have the following,
GroupId
3786
3787
3788
3788
So i need to take 3786, 3787 id's only. If i use distinct() it will take 3788 also. I don't know which method should use in linq.
IQueryable<Sub> subDetails=
from carSub in this.UnitOfWork.Repository<CarSub>().Queryable()
//from pcs in carSub.ConfirmedCarrier.CarrierCandidate.ProductCarrierScores
join p in this.UnitOfWork.Repository<ProductGroup>().Queryable() on carSub.Submission.PlacementID equals p.PlacementID
join pg in this.UnitOfWork.Repository<ProductGroupMember>().Queryable() on p.ProductGroupID equals pg.ProductGroupID
join pcs in this.UnitOfWork.Repository<ProductCarrierScore>().Queryable() on p.ProductGroupID equals pg.ProductGroupID
inside of that JOIN join pcs in this.UnitOfWork.Repository<ProductCarrierScore>().Queryable() on p.ProductGroupID equals pg.ProductGroupID here only i have to use this
pg means ProductGroupMember. in that Member i have to pass the only not repeated values only. Please guide me. I am stuck very much
i would make it like this:
Group them by GroupId;
Get only those which have 1 element in group;
The code will look like this:
var groupIds = subDetails.GroupBy(x=>x.GroupId).Where(x=>x.Count()==1).Select(x=>x.Key)
P.S. There might be some other faster solutions for this, but this is what came to mind first.
You can group by, then narrow down the results to items with count less than 2
For example,
var ids = new List<int> {1, 2, 3, 2, 5, 3, 4};
var itemsNotDuplicate = ids.GroupBy(f => f, t => t,
(k, items) => new {val = k, count = items.Count()}).Where(g => g.count < 2);
you can also you TakeWith
var list = new List<int> { 3786, 3787, 3788, 3788};
var onlyOne=list.TakeWhile(t=> list.Count(l=>l==t)==1);
its a similar approach to using GroupBy, but you only need to use a single lambda expression.

LINQ Join with Multiple From Clauses

When writing LINQ queries in C#, I know I can perform a join using the join keyword. But what does the following do?
from c in Companies
from e in c.Employees
select e;
A LINQ book I have say it's a type of join, but not a proper join (which uses the join keyword). So exactly what type of join is it then?
Multiple "from" statements are considered compound linq statments. They are like nested foreach statements. The msdn page does list a great example here
var scoreQuery = from student in students
from score in student.Scores
where score > 90
select new { Last = student.LastName, score };
this statement could be rewritten as:
SomeDupCollection<string, decimal> nameScore = new SomeDupCollection<string, float>();
foreach(Student curStudent in students)
{
foreach(Score curScore in curStudent.scores)
{
if (curScore > 90)
{
nameScore.Add(curStudent.LastName, curScore);
}
}
}
This will get translated into a SelectMany() call. It is essentially a cross-join.
Jon Skeet talks about it on his blog, as part of the Edulinq series. (Scroll down to Secondary "from" clauses.)
The code that you listed:
from c in company
from e in c.Employees
select e;
... will produce a list of every employee for every company in the company variable. If an employee works for two companies, they will be included in the list twice.
The only "join" that might occur here is when you say c.Employees. In an SQL-backed provider, this would translate to an inner join from the Company table to the Employee table.
However, the double-from construct is often used to perform "joins" manually, like so:
from c in companies
from e in employees
where c.CompanyId == e.CompanyId
select e;
This would have a similar effect as the code you posted, with potential subtle differences depending on what the employees variable contains. This would also be equivalent to the following join:
from c in companies
join e in employees
on c.CompanyId equals e.CompanyId
select e;
If you wanted a Cartesian product, however, you could just remove the where clause. (To make it worth anything, you'd probably want to change the select slightly, too, though.)
from c in companies
from e in employees
select new {c, e};
This last query would give you every possible combination of company and employee.
All the first set of objects will be joined with all the second set of objects. For example, the following test will pass...
[TestMethod()]
public void TestJoin()
{
var list1 = new List<Object1>();
var list2 = new List<Object2>();
list1.Add(new Object1 { Prop1 = 1, Prop2 = "2" });
list1.Add(new Object1 { Prop1 = 4, Prop2 = "2av" });
list1.Add(new Object1 { Prop1 = 5, Prop2 = "2gks" });
list2.Add(new Object2 { Prop1 = 3, Prop2 = "wq" });
list2.Add(new Object2 { Prop1 = 9, Prop2 = "sdf" });
var list = (from l1 in list1
from l2 in list2
select l1).ToList();
Assert.AreEqual(6, list.Count);
}

Linq to SQL brief question

I have a query below. although can anyone point out what "from p" means? and also "var r"?
DataClasses1DataContext db = new DataClasses1DataContext();
var r = from p in db.Products
where p.UnitPrice > 15 // If unit price is greater than 15...
select p; // select entries
r is the composed query - an IQueryable<Product> or similar; note the query has not yet executed - it is just a pending query. var means "compiler, figure out the type of r from the expression on the right". You could have stated it explicitly in this case, but not all. But it wouldn't add any value, so var is fine.
p is a convenience marker for each product; the query is "for each product (p), restricting to those with unit price greater than 15 (where p > 15), select that product (select p) as a result.
Ultimately this compiles as:
IQueryable<Product> r =
db.Products.Where(p => p.UnitPrice > 15);
(in this case, a final .Select(p => p) is omitted by the compiler, but with a non-trivial projection, or a trivial query, the .Select(...) is retained)
The p means each specific item in the collection referenced (db.Products). See from on MSDN.
var is syntactic sugar - it resolves to the type returned from the LINQ query, assigning the type to the variable r. See var on MSDN.
For better understanding of LINQ, I suggest reading through 101 LINQ Samples.
from p means any record from db.Product and var r means the collection of p
overall whole statements means give me all those records(p) from db.Products where p.UnitPrice is greater than 15
see this question to know more about var

How to do a WHERE...IN... clause in LinqToSql?

How can I select multiple elements using a WHERE...IN... type of clause as in
select * from orders where orderid in (1, 4, 5)
in LinqToSql? I'd prefer not to have a lambda expression since they scare me.
LINQ has "Contains" which is like "IN" but expressed the other way round - an element isn't "in" a set, a set "contains" an element.
int[] validIds = { 1, 4, 5 };
var query = from order in db.Orders
where validIds.Contains(order.Id)
select order
This is more simply expressed (IMO) with a lambda though:
int[] validIds = { 1, 4, 5 };
var query = db.Orders.Where(order => validIds.Contains(order.Id));
I realise lambdas are "new" and therefore scary to some extent, but it's really well worth grabbing hold of them with both hands. They're lovely.
int[] arry = new int[] {1,4,5};
var q = from r in orders
where Array.IndexOf(array, orderid) != -1
select r;
or
List<int> lst = new List<int>(new int[] {1,4,5});
var q = from r in orders
where lst.Contains(orderid);
select r;

Categories

Resources