LINQ distinct on 2 fields - linq

I have a LINQ query that returns data and I want to filter based on 2 fields (fkProfileID and fkOrgID) that are often the same. I only want to show 1 record when fkProfileID and fkOrgID match, so it is similar to doing an SQL distinct, but on 2 fields rather than one.
My data will look like this (other fields have been removed) :
fkProfileID fkOrgID
1 1001
1 1001
1 1001
2 1001
2 1001
1 1005
1 1005
So here I want to return only the following:
fkProfileID fkOrgID
1 1001
2 1001
1 1005
Here is my current LINQ (both fields above are in tblUserRights), how do I need to change it to do this?
List<ProfileJSON> lstProfiles = (from r in _database.tblUserRights
join p in _database.LuProfiles on r.fkProfileID equals p.luProfileID
join o in _database.tblOrganisations on r.fkOrgID equals o.pkOrgID
where r.fkUniqueID == intPKUserID
orderby o.OrgDesc, p.ProfileName
select new ProfileJSON
{
SiteID = o.pkOrgID,
SiteName = o.OrgDesc,
ProfileID = p.luProfileID,
ProfileName = p.ProfileName
}).ToList();

You can use .Distinct() after your query
List<ProfileJSON> lstProfiles = (from r in _database.tblUserRights
join p in _database.LuProfiles on r.fkProfileID equals p.luProfileID
join o in _database.tblOrganisations on r.fkOrgID equals o.pkOrgID
where r.fkUniqueID == intPKUserID
orderby o.OrgDesc, p.ProfileName
select new ProfileJSON
{
SiteID = o.pkOrgID,
SiteName = o.OrgDesc,
ProfileID = p.luProfileID,
ProfileName = p.ProfileName
}).Distinct().ToList(); //Distinct here

Related

Need to get max date value from another table to order by product list

I have two tables.
First table is product table as below:
Product
Id Name
1 Apple
2 Desktop
3 Laptop
ProductStatus
Id ProductId LatestUpdatedDate
1 2 01-01-2021
2 2 08-07-2021
I am expecting the below result:
2 Desktop
1 Apple
3 laptop
How to make this query into linq?
Sample that i try
var query= _ProductRepository.Table;
var productStatusHistory = (from psh in _productStatusHistoryRepository.Table
group psh by psh.ProductId into g
select g.OrderByDescending(t => t.CreatedOnUtc).FirstOrDefault());
query = (from q in query
join ps in productStatusHistory on q.Id equals ps.ProductId into l_ps
from ps in l_ps.DefaultIfEmpty()
let index = ps == null ? default(DateTime) : ps.CreatedOnUtc
orderby index
select q);
This query working fine. I want to make this as single query

Linq - Inner join with group with sum

I have 2 tables, first table if transactions
transaction table:
Id LoanId
1 100
The second table I have is a TransactionLeg table
transactionleg table:
ID TransactionId GLAmount
1 1 200
2 1 200
I would like to join the two on the TransactionId column, group by the loanID and sum the GLAmount
So it should produce the following:
LoanId TotalGlAmount
100 400
var investmentsWritten = from transaction in ctx.Transactions
join transactionleg in ctx.TransLegs on transaction.Id equals transactionleg.TransactionId
where
transaction.Class == Transaction.TransactionClasses.WriteOff &&
transaction.Created >= StartDate.Date && transaction.Created <= EndDate.Date
group transaction by transaction.LoanId
into g
select new { Id = g.Key, Value = _____ };
I was wondering what goes where the underline is, the value is transactionleg.GLAmount. I tried g.Sum(x => x.GLAmount) but GLAmount is not recognized, it is highlighted in red stating Cannot resolve symbol GLAmount
It is because GLAmount is in transactionleg not in transaction,
Modify your group by like this:
group new
{
transaction,
transactionleg
}
by new
{
transaction.LoanId
}
and now in Select:
select new
{
Id = g.Key,
Value = g.Sum(x=>x.transactionleg.GLAmount)
}

Need to convert this query to linq or lambda

This query pulls back two columns a userid column and a column of their total sales for the current month.
I need to add a column that ranks them (it would be the exact same as the row #)
And I need to convert this from SQL to LINQ or Lambda.
select pu.userID, SUM(o.OrderTotal) as OrderTotal from ProPit_User pu
inner join SeperateDB.dbo.orders o on pu.salesrepid = o.salesrepid and o.DateCompleted > '2014-05-01' and o.DateCompleted < '2014-05-23'
group by pu.userID
order by SUM(o.OrderTotal) desc
Currently returns:
userID OrderTotal
340 68992.74
318 49575.05
228 42470.88
278 38196.87
291 36220.52
351 34962.32
422 31764.67
178 31433.41
430 30836.77
212 30375.99
To capture the ranking index using SQL, you can simply modify your current sql as such:
SELECT pu.userid,
SUM(o.OrderTotal) AS OrderTotal,
ROW_NUMBER() OVER (ORDER BY SUM(o.ordertotal) DESC) AS [Rank]
FROM ProPit_User pu
INNER JOIN SeperateDB.dbo.Orders o ON pu.salesrepid = o.salesrepid
AND o.DateCompleted > '2014-05-01' AND o.DateCompleted < '2014-05-23'
GROUP BY pu.userid
ORDER BY SUM(o.OrderTotal) DESC
which will yield
userID OrderTotal Rank
340 68992.74 1
318 49575.05 2
228 42470.88 3
etc
Not sure in which context you want to 'convert to LINQ'. If you mean a linq query against these two tables within an EF or Linq-to-Sql context, then these statements will yield the same results as above:
var minDate = new DateTime(2014,5,1);
var maxDate = new DateTime(2014,5,23);
-- the linq to sql query:
-- join on salesrepid, group by userid, sum the ordertotals
var dbQuery = ProPit_Users.GroupJoin(
Orders,
pu => pu.salesrepid,
o => o.salesrepid,
(pu, orders) => new
{
pu.UserId,
OrderTotal = orders.Where(o => o.datecompleted > minDate && o.datecompleted. < maxDate )
.Sum(o => o.ordertotal)
}
)
.OrderByDescending(row => row.OrderTotal)
-- materialize the db query
.ToList();
-- add ranking to the results of the query
var userRankings = dbQuery.Select((row, idx) => new { Rank = ++idx, row.UserId, row.OrderTotal });
which will yield a list of objects:
Rank UserID OrderTotal
1 340 68992.74
2 318 49575.05
3 228 42470.88
etc

Linq Grouping Question

I'm trying to group by categories;
let's say that I have two tables named as follows:
Products, ProductTypes
var foo = (from products in context.PRODUCTS
join producttype in context.PRODUCTTYPE
group producttype by new {producttype.name, producttype.producttypeid, products.productid} into g
select new
{
ProductName = g.Key.name,
ProductID = g.Key.producttypeid,
NumItems = g.Distinct().Count()
});
Here's sample data
Product (productId, Name, ProductTypeID)
-------
1 ProductA 1
2 ProductB 1
3 ProductC 2
4 ProductD 3
ProductType (ProductTypeID, Name)
-----------
1 CategoryA
2 CategoryB
3 CategoryC
ProductSubType (ProductSubtypeID, Name, ProductID)
--------------
1 ProductSubType1 1
2 ProductSubType2 1
3 ProductSubType3 2
4 ProductSubType4 2
5 ProductSubType5 2
6 ProductSubType6 2
7 ProductSubType7 3
my results are as follows
CategoryA 1
CategoryA 1
CategoryB 1
CategoryC 1
I'm expecting the results to be
CategoryA 2
CategoryB 1
CategoryC 1
This is correct, except CategoryA should show up as CategoryA 2.
I'm not sure what simple syntax I'm missing here?
Thanks in Advance.
You are currently grouping by a composite key (name, producttypeid, productid) - any unique combination of these will show up as a separate group. It sounds like you want to group by just producttypeid.
Edit:
First of all your LINQ query seems to be missing a part (the join criteria), it should be more like this to even compile:
var results = (from products in Products
join productType in ProductTypes
on products.ProductTypeID equals productType.ProductTypeId
group productType by new { productType.Name, productType.ProductTypeId, products.ProductId } into g
select new
{
ProductName = g.Key.Name,
ProductID = g.Key.ProductTypeId,
NumItems = g.Distinct().Count()
}).ToList();
Your composite key (Name, ProductTypeId, ProductId) defines the unique elements by which your data will be grouped by. Looking at the sample data you provided you can quickly see that there are four unique combinations:
(Name, ProductTypeId, ProductId)
(CategoryA, 1, 1)
(CategoryA, 2, 1)
(CategoryB, 3, 2)
(CategoryC, 4, 3)
That's why you have the output you provided:
(Name, ProductId)
CategoryA 1
CategoryA 1
CategoryB 1
CategoryC 1
To get the groups you do want to have, a regular Linq group join would do (names normalized to camel case):
var ProductTypeList = (from productType in ProductTypes
join product in Products
on productType.ProductTypeId equals product.ProductTypeID into prod
select new
{
ProductTypeId = productType.ProductTypeId,
Name = productType.Name,
Products = prod.ToList(),
NumItems = prod.Count()
}).ToList();
foreach (var item in ProductTypeList)
{
Console.WriteLine("{0} : {1}", item.Name, item.NumItems);
}
Output:
CategoryA : 2
CategoryB : 1
CategoryC : 1
Let me know if this is what you were after.

LINQ count query returns a 1 instead of a 0

I have the following view:-
CREATE VIEW tbl_adjudicator_result_view
AS
SELECT a.adjudicator_id, sar.section_adjudicator_role_id, s.section_id, sdr.section_dance_role_id, d.dance_id, c.contact_id,
ro.round_id, r.result_id, c.title, c.first_name, c.last_name, d.name, r.value, ro.type
FROM tbl_adjudicator a
INNER JOIN tbl_section_adjudicator_role sar on sar.section_adjudicator_role2adjudicator = a.adjudicator_id
INNER JOIN tbl_section s on sar.section_adjudicator_role2section = s.section_id
INNER JOIN tbl_section_dance_role sdr on sdr.section_dance_role2section = s.section_id
INNER JOIN tbl_dance d on sdr.section_dance_role2dance = d.dance_id
INNER JOIN tbl_contact c on a.adjudicator2contact = c.contact_id
INNER JOIN tbl_round ro on ro.round2section = s.section_id
LEFT OUTER JOIN tbl_result r on r.result2adjudicator = a.adjudicator_id AND r.result2dance = d.dance_id
When I run the following query directly against the db I get 0 in the count column where there is no result
select adjudicator_id, first_name, COUNT(result_id)
from tbl_adjudicator_result_view arv
where arv.round_id = 16
group by adjudicator_id, first_name
However when I use LINQ query I always get 1 in the Count Column
var query = from arv in db.AdjudicatorResultViews
where arv.round_id == id
group arv by new { arv.adjudicator_id, arv.first_name} into grp
select new AdjudicatorResultViewGroupedByDance
{
AdjudicatorId = grp.Key.adjudicator_id,
FirstName = grp.Key.first_name,
Count = grp.Select(p => p.result_id).Distinct().Count()
};
What do I need to change in the View / Linq query.
You're not doing the same thing in the LINQ query as in the SQL. COUNT(result_id) does not count distinct values of result_id - it counts non-null values.
Try this instead:
Count = grp.Select(p => p.result_id).Where(x => x != null).Count()
The point is: you're grouping your data in the LINQ query - and you'll always get at least one group.
That group's Count may be 0 - but the count of groups will be 1.

Resources