How find Max in a query with a join - c#

I created this query, and I don't know how find the last date_attribution
var usertmp = from user in entity.inv_utilisateur
join userbadgetmp in entity.inv_utilisateur_badge on user.u_id equals userbadgetmp.u_id into gj
from userbadge in gj.DefaultIfEmpty()
select new UserEJ
{
u_id = (int) user.u_id,
name = user.name,
date_attrib = userbadge.date_attribution // here I want find the last date
};
for exemple if I have this 2 tables:
inv_utilisateur inv_utilisateur_badge
u_id name u_id date_attribution
1 name1 1 20130911
1 20130807
2 name2 2 20120608
3 name3
I need the result
u_id name date_attribution
1 name1 20130911
2 name2 20120608
3 name3
Edit 1
the type of the field are :
u_id : int,
name : string,
date_attribution : datetime

var usertmp = from user in entity.inv_utilisateur
join userbadgetmp in entity.inv_utilisateur_badge on user.u_id equals userbadgetmp.u_id into gj
from userbadge in gj.DefaultIfEmpty()
group userbadge by new{user.u_id, user.name} into g
select new UserEJ {
u_id = (int)g.Key.u_id,
name = g.Key.name,
date_attrib = g.Max(x => x!= null ? x.date_attribution : <a defaultvalue>)
}
you could also do
var usertmp = from user in entity.inv_utilisateur
let max_dt = (from userbadge in entity.inv_utilisateur_badge
where user.u_id == userbadge.u_id
select userbadge.date_attribution).Max()//??someDefaultvalue if you don't want null
select new UserEJ {
u_id = user.u_id,
name = g.name,
date_attrib = max_dt
}

Sorry for my answer but i am not used in the from clause:
var usertmp = entity.inv_utilisateur
.Join
(
entity.inv_utilisateur_badge,
x=>x.u_id,
x=>x.u_id,
(user,userbadge) => new
{
u_id = user.u_id,
name = user.name,
date_attrib = userbadge.date_attribution
}
)
.GroupBy(x=>new {x.u_id,x.name})
.Select
(
x => new
{
x.Key.u_id,
x.Key.name,
date_attrib = x.Max(z=>z.date_attrib)
}
);

Related

Why can't I select data from my LINQ sub query join?

I am trying to get data from 2 tables using a left join to a nested query. This allows me to get data from Item table but not the cart(nested query) table:
var q = from s in db.Items
join sub in (from c in db.Carts
where c.CartID == 1
group c by c.ItemID into g
select new
{
ItemID = g.Key,
Qty = g.Select(s => s.Qty)
}) on s.ItemID equals sub.ItemID into a
select new ItemViewModel
{
CategoryID = s.CategoryID,
Description = s.Description,
Price = s.Price,
**This being the issue------>>>>>>>** //Qty = a.Select(j => j.Qty),
ItemID = s.ItemID,
ItemName = s.ItemName
};
viewModel = q.ToList();
The query i am trying to acheive is:
select Items.*, Cart.Qty
from Items
left join (select ItemID, Qty from carts where CartID = 1 ) Cart
on Items.ItemID = Cart.ItemID
You can use GroupJoin with SelectMany for LEFT JOIN SQL Query and get the desired output.
var result = db.Items.GroupJoin(db.Carts.Where(x => x.CartID == 1), item => item.ItemID, cart => cart.ItemID,
(item, cart) => new { item, cart })
.SelectMany(x => x.cart.DefaultIfEmpty(), (it, ca) =>
{
return new ItemViewModel
{
ItemName = it.item.ItemName,
Price = it.item.Price,
ItemID = it.item.ItemID,
// ... .... ....
// Fill the required columns from it.Item property..
Qty = ca != null ? ca.Qty : 0
};
}).ToList();
EDIT: The LINQ version with SelectMany.
var result = from s in db.Items
join sub in (from c in db.Carts
where c.CartID == 1
select c)
on s.ItemID equals sub.ItemID into joined
from row in joined.DefaultIfEmpty()
select new ItemViewModel
{
CategoryID = s.CategoryID,
Description = s.Description,
Price = s.Price,
Qty = row != null ? row.Qty : 0,
ItemID = s.ItemID,
ItemName = s.ItemName
};
The C# Fiddle with sample data.
If I'm understanding correctly, and assuming that ItemViewModel.Qty property is just an int, the simplest form of the query you want is:
var q = from item in items
join cart in
(from cart in carts where cart.CartID == 1 select cart)
on item.ItemID equals cart.ItemID into itemCarts
select new ItemViewModel
{
ItemID = item.ItemID,
Qty = itemCarts.Sum(cart => cart.Qty)
};
If you want to only slightly modify/fix your query:
var q = from s in db.Items
join sub in (from c in db.Carts
where c.CartID == 1
group c by c.ItemID into g
select new
{
ItemID = g.Key,
Qty = g.Sum(s => s.Qty)
// or Qty = g.Select(s => s.Qty)
// and below: Qty = a.SelectMany(x => x.Qty).Sum()
})
on s.ItemID equals sub.ItemID into a
select new ItemViewModel
{
CategoryID = s.CategoryID,
Description = s.Description,
Price = s.Price,
Qty = a.Sum(x => x.Qty),
ItemID = s.ItemID,
ItemName = s.ItemName
};

Complicated Linq to SQL Query

I'm struggling to work out what the Linq-to-SQL syntax is for a particular query. I could do this easily in SQL, but I can't quite get the correct syntax in Linq.
I have parent and child records in two database tables, linked by a foreign key. I want my result to return rows based on these rules:
Return exactly 1 row per parent regardless of how many children exist.
Return null/zero values if the child doesn't exist.
Return related data from a child with a null condition. If more than one exists with a null condition then return just the first one.
Return a count of the number of child records with a non-null condition.
I have been playing around with this in .NET Fiddle for a while and I can't get it right. This is what I have so far (ignore the random descriptions!):
IEnumerable<Parent> parents = new Parent[] {
new Parent { ID = 1, Description = "Apple" },
new Parent { ID = 2, Description = "Orange" },
new Parent { ID = 3, Description = "Pear" },
new Parent { ID = 4, Description = "Banana" } };
IEnumerable<Child> children = new Child[] {
new Child { ID = 1, ParentID = 2, Description = "Mercury", Condition = null },
new Child { ID = 2, ParentID = 3, Description = "Venus", Condition = null },
new Child { ID = 3, ParentID = 3, Description = "Earth", Condition = null },
new Child { ID = 4, ParentID = 4, Description = "Mars", Condition = null },
new Child { ID = 5, ParentID = 4, Description = "Saturn", Condition = "> 5" } };
/// What goes here...?
var query = from p in parents
join c in children on p.ID equals c.ParentID into jc
from subchildren in jc.DefaultIfEmpty()
select new Item {
ParentID = p.ID,
Description = p.Description,
PrimaryChildID = subchildren == null ? 0 : subchildren.ID,
SubDescription = subchildren == null ? null : subchildren.Description,
ConditionalCount = 0};
foreach (var item in query)
Console.WriteLine("{0} {1} {2} {3} {4}",
item.ParentID,
item.PrimaryChildID,
item.Description,
item.SubDescription,
item.ConditionalCount);
The output I get from this is:
1 0 Apple 0
2 1 Orange Mercury 0
3 2 Pear Venus 0
3 3 Pear Earth 0
4 4 Banana Mars 0
4 5 Banana Saturn 0
but I want this:
1 0 Apple 0
2 1 Orange Mercury 0
3 2 Pear Venus 0
4 4 Banana Mars 1
Can anyone help me with the correct syntax for this query?
You don't need a left join in your case, you need a group join instead.
According to MSDN:-
The group join is useful for producing hierarchical data structures.
It pairs each element from the first collection with a set of correlated elements
from the second collection.
Do it like this:-
var query = from p in parents
join c in children
on p.ID equals c.ParentID into g
let firstNullElement = g.FirstOrDefault(x => x.Condition == null)
select new
{
ParentID = p.ID,
PrimaryChildID = firstNullElement != null ? firstNullElement.ID : 0,
Description = p.Description,
SubDescription = firstNullElement!= null ? firstNullElement.Description
: String.Empty,
ConditionalCount = g.Count(x => x.Condition != null)
};
Just to explain it properly, here is what will be generated before we project our actual required data using select new { }, (justifies the definition of Group Join):-
ParentId g
----------------------------------------------
1 null
2 ID = 1, ParentID = 2, Description = "Mercury", Condition = null
3 ID = 2, ParentID = 3, Description = "Venus", Condition = null
ID = 3, ParentID = 3, Description = "Earth", Condition = null
4 ID = 4, ParentID = 4, Description = "Mars", Condition = null
ID = 5, ParentID = 4, Description = "Saturn", Condition = "> 5"
Now, since g is holding an IEnumerable of Child elements we can apply filter, project data, count or do whatever we want, as we did in our final statement using select. And also, as we can see there is no point of data coming from different child element.
Here is the complete Working Fiddle.
This should do the thing
var query = (from p in parents
select new
{
ParentID = p.ID,
Description = p.Description,
PrimaryChildID = children.Where(c => c.ParentID == p.ID && c.Condition == null).Count() == 0 ? 0 : children.OrderBy(c=>c.ID).FirstOrDefault(c => c.ParentID == p.ID && c.Condition == null).ID,
SubDescription = children.Where(c => c.ParentID == p.ID && c.Condition == null).Count() == 0 ? null : children.OrderBy(c => c.ID).FirstOrDefault(c => c.ParentID == p.ID && c.Condition == null).Description,
ConditionalCount = children.Where(c => c.ParentID == p.ID && c.Condition != null).Count()
}).ToList();
This is my variant of query:
var query = from p in parents
join c in children on p.ID equals c.ParentID into jc
from subchildren in jc.DefaultIfEmpty()
select new
{
Parent = p,
Subchildren = subchildren
} into itemData
group itemData by itemData.Parent into g
select new Item
{
ParentID = g.Key.ID,
Description = g.Key.Description,
PrimaryChildID = g.Select(_ => _.Subchildren == null ? 0 : _.Subchildren.ID).FirstOrDefault(),
SubDescription = g.Select(_ => _.Subchildren == null ? null : _.Subchildren.Description).FirstOrDefault(),
ConditionalCount = 0
};

Self Join in Linq with null values c#

How can i get the rows that have null in the column used for self join ?
My code is :
IEnumerable<ListClassView> list = from l in lists join lp in lists on
l.ParentListId equals lp.Id
select new ListClassView()
{
Id = l.Id,
ListName = l.ListName,
Description = l.Description,
ParentName = lp.ListName,
IsActive = l.IsActive
};
I am unable to fetch rows where ParentListId=null. Is there a way where i can get all rows ?
Alternative syntax:
var list = lists.GroupJoin(
lists,
l => l.ParentListId,
lp => lp.Id,
(l, lp) => new ListClassView
{
Id = l.Id,
ListName = l.ListName,
Description = l.Description,
ParentName = lp.FirstOrDefault() == null ? null : lp.First().ListName,
IsActive = l.IsActive
});
I found the solution from here by applying a left join :
IEnumerable<ListClassView> list = from l in lists join lp in lists on
l.ParentListId equals lp.Id into lpp
from p in lpp.DefaultIfEmpty()
select new ListClassView()
{
Id = l.Id,
ListName = l.ListName,
Description = l.Description,
ParentName = p.ListName,
IsActive = l.IsActive
};
Now, It gets all rows including those with ParentListId = null

Need a subquery in LINQ

I want to Select all items in this table :
_categoryRepository.Table :
Id Name
1 Birthday
2 Christmas
4 Desktops
6 Notebooks
7 Accessories
9 Cell phones
But, . . I want to exclude any 'Id' from _categoryRepository that match 'EventID' in this table :
_MemberEventRepository.Table
Id MemID EventID
1 1 1
3 1 2
5 1 7
7 4 1
8 4 4
that matches the MemId. So for MemID '1', the results would be :
4 Desktops
6 Notebooks
9 Cell phones
I don't know how to do this in LINQ.
var eventsList = from c in _categoryRepository.Table
join m in _MemberEventRepository.Table on ?????????????
where (m.MemID == currentCustomer)
orderby c.Name
select new MyActiveEvents { Id = c.Id, Name = c.Name };
This the SQL equivalent :
SELECT [Id] ,[Name]
FROM [Category]
WHERE Id NOT IN
(SELECT EventID FROM [Category] c INNER JOIN [MemberEvent] m ON m.[EventID] = c.Id)
Is this possible in LINQ?
Should be something like:
var categories = db.Categories
.Where(c => db.MemberEvents.Count(e => EventID == c.Id) == 0);
Update - using your LINQ-code-fragment:
var eventsList = from c in _categoryRepository.Table
where _MemberEventRepository.Table
.Count(m => m.EventID == c.id) == 0
orderby c.Name
select new MyActiveEvents { Id = c.Id, Name = c.Name }
Instead of Count(...) == 0 it should also be possible to use !Any(...).
Maybe an except would work? I'm not sure which solution will translate into the most efficient sql.
var eventsList = (from c in _categoryRepository.Table
orderby c.Name
select new MyActiveEvents { Id = c.Id, Name = c.Name })
.Except(
from c in _categoryRepository.Table
join m in _MemberEventRepository.Table on c.Id equals m.EventID
where (m.MemID == currentCustomer)
select new MyActiveEvents { Id = c.Id, Name = c.Name });

SQL convert to LINQ to Entities

How do I convert this SQL statement to LINQ to Entities. I cant find a way to union the tables with WHERE clause
SQL:
Declare #DID int, #key varchar(50)
SET #DID = 3
SET #key = ''
SELECT TBL.GID, TBL.GName, TBL.DID FROM
(
SELECT TOP 1 (#DID*10000) AS [GID], '' AS [GName], #DID AS [DID]
FROM dbo.Employees E
WHERE E.DepartmentID=#DID
AND (E.GroupID IS NULL OR E.GroupID = 0)
UNION ALL
SELECT G.GroupID AS [GID], G.GroupName AS [GName], G.DepartmentID AS [DID]
FROM dbo.Groups G
) TBL
WHERE TBL.DID IN (#DID)
AND TBL.GName IN
(
SELECT (CASE WHEN E.GroupID = 0 or E.GroupID IS NULL THEN ''
ELSE (SELECT G.GroupName FROM Groups G WHERE G.GroupID=E.GroupID) END)
FROM Employees E
WHERE E.DepartmentID = #DID
AND (E.FirstName + ' ' + E.LastName) LIKE '%' + #key + '%'
)
ORDER BY TBL.GName DESC
LINQ to Entites:
var Details = (from a in Context.Employees
where a.DepartmentID == DepartmentID
&& (a.GroupID == null || a.GroupID == 0)
select new
{
GID = Convert.ToInt32(DepartmentID * 10000),
GName = "",
DID = a.DepartmentID
}
).Concat(
from a in Context.Groups
select new
{
GID = a.GroupID,
GName = a.GroupName,
DID = DepartmentID
}
);
The anonymous type created in the results of each query are different types, so you can't Concat() them. You could define a common Group class like this...
class Group
{
public int ID { get; set; }
public int DepartmentID { get; set; }
public string Name { get; set; }
}
Then pull out the sub-queries and create the results as instances of the above class...
int deptID = 99;
string key = "foo";
var r1 = (from a in Context.Employees
where a.DepartmentID == deptID
&& (!a.GroupID.HasValue || a.GroupID == 0)
select new Group()
{
ID = a.DepartmentID * 10000,
Name = string.Empty,
DepartmentID = a.DepartmentID
}
).Take(1);
var r2 = (from a in Context.Groups
where a.DepartmentID == deptID
select new Group()
{
ID = a.GroupID,
Name = a.GroupName,
DepartmentID = a.DepartmentID
}
);
var results = r1.Concat(r2); // UNION ALL the above 2 sets of results
Then create the filter set and finally use it filter the results from above...
var filter = (from e in Context.Employees
join g in Context.Groups on g.GroupID equals e.GroupID into eg
from subgrp in eg.DefaultIfEmpty()
where e.DepartmentID == deptID
&& (e.FirstName + " " + e.LastName).Contains(key)
select e.GroupID.HasValue && e.GroupID != 0 ? subgrp.GroupName : string.Empty
).Distinct().ToList();
results = from a in results
where filter.Contains(a.Name)
orderby a.Name descending
select a;
Feel free to comment if doesn't do exactly what you need.

Categories

Resources