Multiple joins into one list - c#

With the query below I am doing multiple joins and selecting them all. I want to return this result into a list, so in this case I would have a List with a count of three, assuming that there are three addresses associated with this single customer id order...Right now the query works but I put exp.ToList() it gives me essentially a 2d list ( a list with a single element in which this element is a type list of 3 elements. I'm sure there's a good way to do this... thoughts ?
var exp = (
from t in this.reposOrders.All()
join p1 in this.reposAddress.All()
on t.AddressPrimary equals p1.AddressID into pp1
from p1 in pp1.DefaultIfEmpty()
join p2 in this.reposAddress.All()
on t.AddressSecondary equals p2.AddressID into pp2
from p2 in pp2.DefaultIfEmpty()
join p3 in this.reposAddress.All()
on t.AddressThird equals p3.AddressID into pp3
from p3 in pp3.DefaultIfEmpty()
where t.CustomerID == customerID
select new { p1, p2, p3 }
);

Can you use SelectMany? There are many linq samples here http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx

What you want to do suffers from poor normalization; AddressPrimary, AddressSecondary, and AddressThird should not be fields of Orders (I'm assuming order from your line from t in this.reposOrders.All()), but should be contained in a weak entity or join table.
That said, you can probably get what you want with the following query:
var primary = from t in this.reposOrders.All() where t.CustomerID == customerID select t.AddressPrimary;
var secondary = from t in this.reposOrders.All() where t.CustomerID == customerID select t.AddressSecondary;
var tertiary = from t in this.reposOrders.All() where t.CustomerID == customerID select t.AddressThird;
var ids = primary.Union(secondary).Union(tertiary);
var addresses = from a in this.reposAddress.All() where ids.Contains(a.AddressID) select a;

Related

Left join with where clause in linq

I am trying to do a left join with a where clause in linq.
I have leadsQuery table with 2500 rows. I want to join the LeadCons table into it. For a lead there can be multiple entries in the LeadCons table, hence I want to join only when the Status match. Else I want the fields to be NULL.
var data = from lead in leadsQuery
join lcs in context.LeadCons on lead.ID equals lcs.LeadId into leadsWithCons
from lcs in leadsWithCons.DefaultIfEmpty()
where lead.Status == lcs.Status
select new
{
LeadId = lead.ID,
Source = lead.Source.ToString(),
};
This query gives me ~1500 rows and leadsQuery has 2500. What am I doing wrong here?
A late answer, hoping it is still helpful:
First, you aren't selecting any values from LeadCons, so what is the purpose of a join?
I shall assume maybe you want to extend your select, so let us say you want to select the property foo, so my next question: Why do you need a left join in your case? You can simply do a select:
var data = from lead in leadsQuery
select new
{
Foo = context.LeadCons.Where(lcs => lead.Status == lcs.Status).SingleOrDefault().foo
LeadId = lead.ID,
Source = lead.Source.ToString(),
};
This way you have the same number of items and for each item the desired foo value.
Have you tried just changing the your join to a join with multiple conditions, and then removing the where 'status equal status'
from lead in leadsQuery
join lcs in context.LeadCons on new {
p1 = lead.ID,
p2 = lead.Status
}
equals
new {
p1 = lcs.LeadId,
p2 = lcs.Status
}
you can have a look at this nice article:
https://smehrozalam.wordpress.com/2010/04/13/linq-how-to-write-queries-with-complex-join-conditions/

Linq get array and sum as part of the returned dataset

I have this Linq query:
var result = from game in db.Games
join gameevent in db.Events
on game.GameId equals gameevent.GameId
join birdLife in db.EventBirdCaptures
on gameevent.EventId equals birdLife.EventId
select new
{
game.GameId,
game.Name,
gameevent.LocationId, - array of all the location id's based on the game id
birdLife.BirdId - sum of all the birdids based on event id
};
For the last two results, location id and bird id I want to get array of the id's for the location id and the sum of bird ids.
How is that possible to be achieved in Linq?
It's not clear to me what you are asking, but if I understand what you want you can use join-into (group join) instead of join:
var result = from game in db.Games
join gameevent in db.Events
on game.GameId equals gameevent.GameId into events
from _event in events
join birdlife in db.EventBirdCaptures
on _event.EventId equals birdlife.EventId into birds
select new
{
game.GameId,
game.Name,
locations = events.Select(e => e.LocationId),
birds = birds.Sum(b => b.BirdId)
};

Entity framework - select by multiple conditions in same column - referenced table

Example scenario:
Two tables: order and orderItem, relationship One to Many.
I want to select all orders that have at least one orderItem with price 100 and at least one orderItem with price 200.
I can do it like this:
var orders = (from o in kontextdbs.orders
join oi in kontextdbs.order_item on o.id equals oi.order_id
join oi2 in kontextdbs.order_item on o.id equals oi2.order_id
where oi.price == 100 && oi2.price == 200
select o).Distinct();
But what if those conditions are user generated?
So I dont know how many conditions there will be.
You need to loop through all the values using a Where and Any method like this:
List<int> values= new List() { 100, 200 };
var orders = from o in kontextdbs.orders
select o;
foreach(int value in values)
{
int tmpValue = value;
orders = orders.Where(x => kontextdbs.order_item.Where(oi => x.id == oi.order_id)
.Any(oi => oi.price == tmpValue));
}
orders = orders.Distinct();
List<int> orderValues = new List() { 100, 200 };
ObjectQuery<Order> orders = kontextdbs.Orders;
foreach(int value in orderValues) {
orders = (ObjectQuery<Order>)(from o in orders
join oi in kontextdbs.order_item
on o.id equals oi.order_id
where oi.price == value
select o);
}
orders = orders.Distinct();
ought to work, or at least that's the general pattern - you can apply extra queries to the IObjectQueryables at each stage.
Note that in my experience generating dynamic queries like this with EF gives terrible performance, unfortunately - it spends a few seconds compiling each one into SQL the first time it gets a specific pattern. If the number of order values is fairly stable though then this particular query ought to work OK.

Set operation: how to filter a collection based on a COMBINED set of ints

I have this expression:
var result = from pav in ProductAttributes
join id in valueIds
on pav.AttributeValueID equals id
select pav.ProductImageID;
which works up to a point. The issue is that the collection ProductAttributes contains the same product many times, for each attribute. It's structure is:
ID - unique
ProductID
ProductAttributeValueID
ProductImageID
So a Product may appear many times in the collection. I want the result to actually filter OUT all the products that DON'T have any matches at all in valueIds (which is a list of ProductAttributeValueIDs).
So I want to ONLY return products that have ALL of the COMBINED valueIds, not just ANY of them, which is what the above linq expression is doing.
PS I can post SQL code that shows what I mean in SQL if that helps!
#devgeezer posted an answer which was close enough but it only worked for one value.
I ended up with the code below, which works. I group on the ProductID, then use that in a 2nd query to filter the original collection:
var result =
from pav in ProductAttributeValues
join id in valueIds
on pav.AttributeValueID equals id
group pav by pav.ProductID into gj
where gj.Count() == valueIds.Count()
select gj.Key;
var imageIds = from pav in ProductAttributeValues
join id in result
on pav.ProductID equals id
select pav.ProductImageID;
You might try a group and filter approach something like the following:
var result =
from pav in ProductAttributes
join id in valueIds
on pav.AttributeValueID equals id
group pav by pav.ProductImageID into gj
where gj.Count() == valueIds.Count()
select gj.Key;

Conditional Join In LINQ?

I am trying to write a query that grabs information from one database and joins it to information in a different database.
TableA
idA
valueA
idB
TableB
idB
valueB
The tricky part is that in TableA, idB isn't always defined, so when I do a normal join, I only get results where TableA has a idB value. What I want is to be able to grab all of the information from TableA even if it doesn't have a corresponding idB value.
Here is a query expression syntax version of the left join to follow up on tvanfosson's answer.
var query = from rowA in db.TableA
join rowB in db.TableB
on rowA.idB equals rowB.idB into b
from item in b.DefaultIfEmpty()
select new
{
idA = rowA.idA,
valueA = rowA.valueA,
idB = rowA.idB,
valueB = item != null ? item.valueB : 0 // or other default value
};
Use a left outer join by checking if the value returned from the right hand side is null and supplying a default value for that case.
var q = db.TableA.Join( db.TableA,
a => a.idB,
b => b.idB,
(a,b) => new
{
A = a.ValueA,
B = b == null ? null : b.ValueB
});
You can do a left outer join in LINQ with SelectMany (directly calling Queryable methods) or in comprehension syntax join ... into:
var results = from a in db.TableA
join b in db.TableB on a.idB equals b.idB
into found
select new {
A = a,
Bs = found
};
In the output Bs will be IEnumerable<typeof-db-TableB>
Left Join Example:
var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product{Name = String.Empty, CategoryID = 0})
select new { CatName = category.Name, ProdName = item.Name };

Categories

Resources