How to do a WHERE...IN... clause in LinqToSql? - c#

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;

Related

How to Convert Linq to Lambda Expression

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.

Entity Framework + LINQ Expression outer join error

i want to create a left outer join for a linq expression that query data from database via entity framework. this is the linq expression. basically what I am trying to do is search problem_vehicle_id from problemVehiclesTicket in Problems table to see if it exists, if it doesn't exists, i want to return a problem object that is null/empty. Basically I believe it is left outer join.
var ticketsDetails = (from tickets in DbContext.tickets
join problemVehiclesTicket in DbContext.problem_vehicle on tickets.tickets_id equals problemVehiclesTicket.tickets_id
join problems in DbContext.problem on problemVehiclesTicket.problem_vehicle_id equals problem.problem_vehicle_id into problemGroup
from problems in problemGroup.DefaultIfEmpty(new problem { })
where (tickets.tickets_id == ticketsId)
select new TicketsDetails
{
Ticket = tickets,
ProblemVehicle = problemVehiclesTicket,
Problems= problem,
}).ToList();
Problem is a class that mirrors that of the Problem table in database
`Problem`
id (int), description (string), type (short)
The error i got is "The entity or complex type 'SPOTS_Repository.speeding_offence' cannot be constructed in a LINQ to Entities query." The source is from Entity Framework.
any help is greatly appreciated.
The type problem in your case is a mapped entity. Therefore, you cannot project onto it. You can use an anonymous type or another non-mapped class (DTO).
Because in your DefaultIfEmpty method you are constructing a new problem, which is a mapped entity, this not allowed.
Fix
You do not need to pass anything to DefaultIfEmpty method. Actually in your case, you are not even allowed because the only thing you can pass is problem and that is mapped. Therefore, use .DefaultIfEmpty() without creating a new problem.
More Belabor
Here is an example, which will clarify the usage of DefaultIfEmpty:
Option 1: DefaultIfEmpty() with No Parameter
var list1 = new List<int> { 1, 2, 3, 6, 4 };
var list2 = new List<int> { 4, 1, 2 };
var selection =
from l1 in list1
join l2 in list2 on l1 equals l2 into joined
from j in joined.DefaultIfEmpty()
select j;
Output: 1, 2, 0, 0, 4
Why? Because 3 and 6 are not found and DefaultIfEmpty for an integer returns a 0.
Option 2: DefaultIfEmpty() with Parameter
In some cases we may want to indicate that if the item is not found in the join, what to return instead. We can do that by sending a single parameter to DefaultIfEmpty method like this:
var list1 = new List<int> { 1, 2, 3, 6, 4 };
var list2 = new List<int> { 4, 1, 2 };
var selection =
from l1 in list1
join l2 in list2 on l1 equals l2 into joined
from j in joined.DefaultIfEmpty(99) //<-- see this
select j;
Output: 1, 2, 99, 99, 4 Why? Because 3 and 6 are not found and we instructed DefaultIfEmpty to return a 99 in that case.
Please note that DefaultIfEmpty is a generic method. In my case it required an int because I am joining to the second list which is a List of int(s). In your case it is problem(s) but that is mapped. Therefore, you cannot construct it in your query.
Here is another example:
var depts = new List<Department>
{
new Department { Name = "Accounting" },
new Department { Name = "IT" },
new Department { Name = "Marketing" }
};
var persons = new List<Person>
{
new Person { DeptName = "Accounting", Name = "Bob" }
};
var selection2 =
from d in depts
join p in persons on d.Name equals p.DeptName into joined2
// See here DefaultIfEmpty can be passed a Person
from j2 in joined2.DefaultIfEmpty(new Person { DeptName = "Unknown", Name = "Alien" })
select j2;
foreach(var thisJ in selection2)
{
Console.WriteLine("Dept: {0}, Name: {1}", thisJ.DeptName, thisJ.Name);
}
Output:
Dept: Accounting, Name: Bob
Dept: Unknown, Name: Alien
Dept: Unknown, Name: Alien
<== Fiddle Me ==>
Public class problem()
{
public int id;
public string description;
public short type;
}
.DefaultIfEmpty(
new problem()
{
Id = ticketsId,
Description = string.empty,
});
create class and make use of that in linq query
Hope it helps you.

Join for List<Array> in lambda expression chain syntax

I am an amateur at Joins, but I am trying to use expression chain syntax instead of a LINQ statment. Most examples I find have used arrays or list of classes { List<class> }; but nothing for a list of arrays { List<array> }
List<int[]> needHelp = new List<int[]>{
new int[3] { 10, 20, 50},
new int[3] { 10, 21, 53},
new int[3] { 10, 22, 55},
new int[3] { 11, 20, 60},
new int[3] { 11, 22, 51} };
List<int[]> ghosts = new List<int[]>{
new int[3] { 10, 45, 65},
new int[3] { 11, 34, 60} };
The LINQ "query" syntax that works is:
List<int[]> result = (from h in needHelp join g in ghosts on h[0] equals g[0]
where h[1] == 21 select g).ToList();
But this "Method" expression chain syntax isn't working for me:
List<int[]> result = needHelp.Join(ghosts, x=>x[0], y=>y[0], (x,y) => y ).Where(x => x[1] == 21).ToList();
For those interested I have found that this lambda expression chain can print out a List of arrays without having to use two foreach loops.
result.ForEach( x => { Array.ForEach(x, e => Console.Write(e + " ") ); Console.WriteLine();} );
Ok well I think I found my own solution, and it was by changing the location of the where clause. But what is the reason the Where has to come before the join and not work after? I read on a post that if this was a database call the where class being before ".Join" then it is processed on the server and not the client. I assume then that trying to use it after the Join it is out-of-scope of the data that is left, which in this instance would be y (List<int[]> ghosts).
Joins and Wheres are not interchangeable in general.
If you read your expression chain "out loud", it would read something like this: first get me all arrays in ghosts that match up a first element with something in needHelp, and then select from that those arrays which have the second element equal to 21.
So at the point after the Join, you are only left with arrays that come from the ghosts List. Your WHERE clause then returns nothing, since nothing in ghosts has second element equal to 21. You are checking for that in the needHelp List.
I would recommend that you do swap the Join and the Where:
List<int[]> result = needHelp.Where(x => x[1] == 21).Join(ghosts, x=>x[0], y=>y[0], (x,y) => y ).ToList();
In case it was a source of confusion for you, don't think that the x and y variables in the functions mean anything over multiple functions. Your Where call related x to needHelp, but that doesn't mean that the x in the Join function relates to needHelp; it references the output of the Where, which are elements from ghosts.
Your Join method isn't the translation of the query syntax you gave.
Your query filter on h[1] (x[1] in the Join) but you select only y (g in your query) so the Where after that applies on the wrong thing.
Here is the direct translation of your query :
List<int[]> result =
needHelp
.Join (ghosts, x => x[0], y => y[0], (x, y) => new { x, y })
.Where (anon => anon.x[1] == 21)
.Select (anon => anon.y)
.ToList ();
The exact method syntax equivalent of this query syntax
from h in needHelp join g in ghosts on h[0] equals g[0]
where h[1] == 21
select g
is something like this:
needHelp.Join(ghosts, h => h[0], g => g[0], (h, g) => new { h, g })
.Where(x => x.h[1] == 21)
.Select(x => x.g);
The query syntax uses so called "transparent indentifiers" which hide those intermediate anonymous types, and that's why is preferable for queries involving joins.
Speaking about joins and where in general, IMO it's always better to apply the filters before joining, especially in LINQ to Objects, because database query optimizers will rearrange the filters and join operations anyway. So a better query (from both performance and memory allocations) would be:
needHelp.Where(h => h[1] == 21).Join(ghosts, h => h[0], g => g[0], (h, g) => g);

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.

How do I get results from a Linq query in the order of IDs that I provide?

I'm looking to get query results back from Linq in the order that I pass IDs to the query. So it would look something like this:
var IDs = new int [] { 5, 20, 10 }
var items = from mytable in db.MyTable
where IDs.Contains(mytable.mytableID)
orderby // not sure what to do here
select mytable;
I'm hoping to get items in the order of IDs (5, 20, 10).
(Note this is similar to this question, but I would like to do it in Linq instead of SQL)
I would just do it outside of the SQL query. There's really no benefit to getting it done on the SQL Server in this case.
var items = (from mytable in db.MyTable
where IDs.Contains(mytable.mytableID)
select mytable)
.ToArray()
.OrderBy(x => Array.IndexOf(ids, x.mytableID));
This should work with LINQ-to-objects; I'm not sure if it does with LINQ-to-SQL though:
var ids = new int [] { 5, 20, 10 };
var result = from item in items
where Array.IndexOf(ids, item.Id) >= 0
orderby Array.IndexOf(ids, item.Id)
select item;

Categories

Resources