Linq join two tables and count column - c#

I have two tables.
TableA
TableAId value value2
1 a b
2 aa bb
TableB
TableBId TableAId Status
1 1 success
2 1 success
3 2 failed
4 2 failed
I am trying to create list like
TableAId value value2 successCount errorCount
1 a b 2 0
2 aa bb 0 2
This is the query which I am trying to create but I am getting wrong results.
var query = (from a in db.TableA.AsEnumerable()
join b in db.TableB.AsEnumerable()
on a.TableAId equals b.TableAId
select
new
{
TableAId = a.TableAId,
value = a.value,
value2 = a.value2,
successCount = b.Status.Count(t => t.ToString() == "success"),
errorCount = b.Status.Count(t => t.ToString() == "failed")
}).ToList();
Any help how I can correct the query would be appreciated.
Thanks in advance

You need to group your rows by something first, otherwise the count doesn't make sense.
from a in db.TableA
join b in db.TableB on a.TableAId equals b.TableAId
group b by a into g
select new
{
TableAId = g.Key.TableAId,
value = g.Key.value,
value2 = g.Key.value2,
successCount = g.Count(t => t.Status == "success"),
errorCount = g.Count(t => t.Status == "failed")
}
I also removed AsEnumerable calls to move the join, grouping and counting to the database - your query brings all the rows into application memory before performing the query using LINQ to Objects, which is in 99.9% of cases not what you want.

Related

convert detailed table row to column linq to sql lambda expression (master detail relationship)

Suppose we have a master-detail relationship as follows
**Order Table**
OrderId
OrderDate
**OrderItem Table**
OrderItemId
OrderId
ItemId1
Price1
ItemId2
Price2
ItemId3
Price3
**Item Table**
ItemId
ItemName
Each order can have a maximum of 3 order items. Hence, the OrderItem Table is designed as above. How can I write a LINQ to SQL lambda expression that gives the following output?
OrderId -- OrderDate -- Item1Name -- Item1Price -- Item2Name -- Item2Price -- Item3Name -- Item3Price
1 8/27/2020 Item1 30 Item2 40
2 8/27/2020 Item1 20 Item5 15 Item8 40
3 8/27/2020 Item4 30
The solution below is not the best, it can be improved if we know more information what kind of technology are you using (.NET or .NETCore) so please answer the questions above and we can help you more. Currently this is the best that I can do for you:
var resultSet = (from orderItem in dataContext.OrderItem
join order in dataContext.Order on orderItem.OrderId equals order.OrderId
let firstItem = (from item in dataContext.Item
where item.ItemId == orderItem.ItemId1
select item).FirstOrDefault()
let secondItem = (from item in dataContext.Item
where item.ItemId == orderItem.ItemId2
select item).FirstOrDefault()
let thirdItem = (from item in dataContext.Item
where item.ItemId == orderItem.ItemId3
select item).FirstOrDefault()
let firstItemExists = firstItem != null
let secondItemExists = secondItem != null
let thirdItemExists = thirdItem != null
select new
{
OrderId = order.OrderId
OrderDate = order.OrderDate,
Item1Name = firstItemExists
? firstItem.ItemName
: string.Empty
Item1Price = firstItemExists
? firstItem.ItemPrice
: null
Item2Name = secondItemExists
? secondItem.ItemName
: string.Empty
Item2Price = secondItemExists
? secondItem.ItemPrice
: null
Item3Name = thirdItemExists
? thirdItem.ItemName
: string.Empty
Item3Price = thirdItemExists
? thirdItem.ItemPrice
: null
});
This query should do what you want, but I did not test if LINQ to SQL can translate it:
var ans = (from o in Orders
join oi in OrderItems on o.OrderId equals oi.OrderId
join i1 in Items on oi.ItemId1 equals i1.ItemId into i1j
from i1 in i1j.DefaultIfEmpty()
join i2 in Items on oi.ItemId2 equals i2.ItemId into i2j
from i2 in i2j.DefaultIfEmpty()
join i3 in Items on oi.ItemId3 equals i3.ItemId into i3j
from i3 in i3j.DefaultIfEmpty()
select new {
o.OrderDate,
Item1Name = i1.ItemName,
Item1Price = oi.Price1,
Item2Name = i2.ItemName,
Item2Price = oi.Price2,
Item3Name = i3.ItemName,
Item3Price = oi.Price3,
})
.ToList();

Complex Linq Query Update as DateTime

There are A and B tables that are related to each other. I want to create a linq query that will update the Status value in the A table if the entire row of relationship lines with the AID column in the B table is equal to or smaller than today's date in the Date field.
For example, according to the table below, the Status values of the rows with ID value 1 (AAA) and 2 (BBB) in Table A will be 1. Its Status value will not change because the line with ID value 3 (CCC) is not smaller than the current date of all the related rows in the B table.
How can I write the most stable and performance linq query?
Today : 2018-7-10
A Table
ID Name Status
1 AAA 0
2 BBB 0
3 CCC 0
B Table
ID AID Date
6 1 2018-5-3
7 2 2018-6-2
8 2 2018-6-4
9 3 2018-10-12
10 3 2018-7-7
Grouping TableB on AID
Selecting the "Max" date in each group.(Each unique AID)
Compares the selected dates with the corresponding Id in Table A.
Sets the Status value to true if the date is less or equal to the current date.
TableB.GroupBy(x => x.AId).Select(group => new { identifier = group.Key, MaxDate = group.Max(m => m.Date) }).ToList().ForEach(y =>
{
if (y.MaxDate <= DateTime.Now.Date)
{
TableA.Where(g => g.Id == y.identifier).First().Status = true;
}
});
This will select AIDs from Table B where Date is samller than now.
we select records from table A where its ID is in List from
previous step
Then we update Status value
A.Where ( a => B.Where( b => b.Date <= DateTime.Now).Select(b => b.AID).Contains(a.ID)).ForEach( a => a.Status = 1 )
/*Fetching those aS Who meet the condition. */
var aList1=(from b in dbset.Bs.Where(x=>x.Date<DateTime.Now)//TimeZone may vary
join a in dbSet.As
on b.AID equals a.ID
select a);
/*Fetching those aS Who don't meet the condition. */
var aList2=(from b in dbset.Bs.Where(x=>x.Date>=DateTime.Now)//TimeZone may vary
join a in dbSet.As
on b.AID equals a.ID
select a);
/*Removing those aS from list1 which occured in list2 */
var aFinalList=(aList1.Except(aList2)).ToList();
/*Updating status */
aFinalList.ForEach(x=>x.Status=1);
aFinalList.SaveChanges();
You can use GroupJoin extension in Lambda to Join the A and B tables then use All extension with your condition (date <= Today or any condition) then update the Status. Something like,
var lstResult = lstA.GroupJoin(lstB, a => new { a.Id }, b => new { Id = b.AId }, (a, b) => new { a, b })
.Select(x =>
{
if (x.b.All(y => y.Date <= DateTime.Now)) //Actual condition here.
{
x.a.Status = true;
return x.a;
}
else return x.a;
});
C# fiddle with sample data.

How to retrieve all columns from table1 and matching columns from table2(Left outer join) using Linq

I have to retrieve all the columns from table1 and matching columns from table2. I have a stored procedure as :
alter Procedure [dbo].[usp_Property]
#UserId bigint =null
As
Begin
select P.PID, P.PropertyName, P.SBUArea, P.ListedOn,
P.Availability, P.Price, F.UserID, F.PID as FavProjId
from dbo.Property P left outer join dbo.Favorite F
on (F.PID=P.PID And F.UserID=#UserId)
I want to get Linq query for the same. So far I tried with something like
//User Id comes from session..
//var userId
var result=(from p in Properties
join f in Favorites
on p.PID equals f.PID into r
from r1 in r.DefaultIfEmpty()
where r1.UserID==userId
select new
{
p.PID,
p.PropertyName,
p.SBUArea, p.ListedOn,
r1.UserId
});
Can anyone please correct me. I want to use left outer join or any other alternate thing here.
If I beautify your SP's code, I get this:
DECLARE #UserId int
SET #UserId = 12435
SELECT
P.PID
,P.PropertyName
,P.SBUArea
,P.ListedOn
,P.Availability
,P.Price
,F.UserID
,F.PID AS FavProjId
FROM Property AS P
LEFT JOIN Favorite AS F
ON (F.PID=P.PID AND F.UserID = #UserId)
Now I wonder if you need that UserId in the WHERE clause of the SQL, or really in the join.
But anyway, here the LINQ-equivalent of exactly that SQL:
System.Int64 __UserId = 12435;
var query = (
from P in Repo.Property
from F in Repo.Favorite
.Where(fav=> fav.PID == P.PID && fav.UserID == __UserId)
.DefaultIfEmpty() // <== makes join left join
select new
{
PID = P.PID
,PropertyName = P.PropertyName
,SBUArea = P.SBUArea
,ListenOn = P.ListedOn
,Availabiity = P.Availability
,Price = P.Price
,UserId = F.UserID
,FavProjId = F.PID
}
);
var data = (query).ToList();
Use anonymous objects in your selection
var result = from t in table1
join x in table2
on t.id equals x.id
select new { id = t.id, col1 = t.col1, col2 = x.col2 }
If you will put the where clause after join you may get null reference exception because DefaultIfEmpty returns default value for non matching rows. You can filter the records before joining itself like this:-
var result=(from p in Properties
join f in Favorites.Where(x => x.UserID == userId)
on p.PID equals f.PID into r
from r1 in r.DefaultIfEmpty()
select new
{
p.PID,
p.PropertyName,
p.SBUArea,
p.ListedOn,
r1.UserId
});
Please note you need to access properties of Favorites using r1.
Update:
As far as I have understood you need all records from Property table and only matching rows from Favorite table. But you have a filter on your Favorite table so the ultimate data source will differ. Let me make my point clear by this example:-
Suppose you have following data in Property table:-
PID PropertyName Availability Price
1 aaa true 20
2 bbb false 10
3 ccc true 50
4 ddd false 80
5 eee true 55
6 fff false 70
and Favorite table like this:-
FID PID UserId
1 4 1001
2 2 1005
3 5 1007
And let's say you want all records for UserId 1005, then the result should contain all the property Id's from 1 till 6 even if UserId 1005 doesn't match for property Id's 4 & 2 right? So the query above is as per this understanding. Check this Fiddle with same example and output.

Linq Query for EAV design table

I had a situation to use EAV design tables and I am new to this design,I am struck with a select query. Below is my query structure and data.
TABLE1:
Id KeyName
1 Name
2 Age
TABLE2:
ID TABLE1_ID VALUE
1 1 ABC
2 2 12
3 1 CDF
4 2 14
5 1 XYZ
6 2 13
7 1 CSF
8 2 10
EXPECTED OUTPUT: Get all the values which are greater than 12 AND Value contains "C".
i.e.,
Table2_ID Result Table1_KeyName
1 ABC Name
2 12 Age
3 CDF Name
4 14 Age
Options I tried are:
Var temp = (from c in Table2
where c.Value > 12 && c.Table1.KeyName.Contains("C")
Select new
{
ID = c.ID,
Result = C.Value
});
the above query didn't returned any result, as filters(in where clause) are across rows. I even tried "OR" condition in where clause, it returns me everything. Please do help me.
Your query is wrong, did you type it in here or copy and paste it from your work?
Do you have this table setup in an ORM such as Entity Framework? So that there is a relationship setup between table1 and table2, so you don't have to 'join' them?
To be more 'correct' it should be...
Var temp = (from c in Table2
where c.Value > 12 && c.Table1.Name.Contains("C")
Select new
{
ID = c.ID,
Name = c.Table1.Name,
Value = c.Value
});
Or if the relationship isn't in an ORM your using explicitly specify the join as follows:
Var temp = (from c in Table2
join c1 in Table1 on c.Table1_ID equals c1.Id
where c.Value > 12 && c.Table1.Name.Contains("C")
Select new
{
ID = c.ID,
Name = c.Table1.Name,
Value = c.Value
});
Edit: then it should be an OR, not AND
Var temp = (from c in Table2
where c.Value > 12 || c.Value.Contains("C")
Select new
{
ID = c.ID,
Result = c.Value,
KeyName = c.Table1.Name
});

How to return value from 2 tables in one linq query

please consider this table:
PK_Id Number Year Month Value
-------------------------------------------------------------------------
1 1 2000 5 100000
410 4 2000 6 10000
8888 1 2001 5 100
I Id=8888 and now I want to first select record with Id=8888 and second select previos year of that record*(I mean Id=1)*. How I can do this with linq and one query.
basically we have some queries that first it should find a value from a table (that may be not PK) and find Corresponding records in another tables. How I can do this with linq and one reference to database.
thanks
from a in Record
where a.PK_Id == 8888
from b in Record
where b.Number == a.Number && b.Year == a.Year - 1
select new { Current = a, Previous = b }
or
Record
.Where(a => a.PK_Id == 888)
.SelectMany(a =>
Record
.Where(b => b.Number == a.Number && b.Year == a.Year - 1)
.Select(b => new { Current = a, Previous = b })
If I understand your question right, then you need to filter the data of one table and join two tables.
You can join the tables and filter your data
var query = from c in Table1
join o in Table2 on c.Col1 equals o.Col2
where o.Col3 == "x"
select c;
or you can filter your data from one table and then join the tables (result will be the same)
var query = from c in Table1.Where(item => item.Col3 == "x")
join o in Table2 on c.Col1 equals o.Col2
select c;

Categories