Simplifying LINQ query in C# - c#

Table1
Table1ID Name Graduation Version Hobbies
1 A Degree 1 B
2 A Degree 2 C
3 A Degree 3 D
Table2
Table2ID Table1ID Name Graduation Version Address Surname Date
1 1 A Degree 1 A A 08-10-2019
2 2 A Degree 2 A A 08-10-2019
3 3 A Degree 3 A A
//I want to check if any version greater than highest version exists in Table1 .where Date column is not null in Table2
Suppose for the combination of Name and Degree , the highest version is 2 in Table2 since Date is null for Table2, I want to check if any record greater than 2 exists in Table1, if yes add it to a new List
Here is what I am doing.
List<Table2> groupByTable2 = //Operations on Table2 and get highest Version record from db
List<Table1> check = new List<Table1>();
List<Table1> check2 = await _table1.GetAll().ToListAsync();
Foreach(var a in groupByTable2)
{
List<Table1> check4 = check2.Where(x => x.Name == a.Name && x.Graduation == a.Graduation).ToList();
If(check4.Any(x=>x.Version > a.Version))
{
check.Add(check2.Where(x=>x.Table1ID == a.Table1ID).First());
}
}
Now my check contains a record where ID is 3. But is there any simpler way to achieve this in simpler way with readability and performance?

I hope I understood what you are trying to achieve. You could try the following.
var result = table2.Where(x=>x.Date!=null)
.GroupBy(x=> new {x.Name, x.Graduation})
.SelectMany(x=> x.OrderByDescending(c=>c.Version).Take(1))
.Join(table1,t2=>t2.Table1ID,t1=>t1.Table1ID,(t2,t1)=>t1)
.ToList();
result.AddRange(table1.Where(x=> result.Any(c=>c.Name.Equals(x.Name)
&& c.Graduation.Equals(x.Graduation)
&& c.Version < x.Version)));
The idea is to first use GroupBy and Join to get the List of Items with highest Version number in Table1 that has a valid date in Table2. Then, use List.AddRange to add remaining higher versions from Table1.

Related

group by linq to entity query to get one record having latest timestamp by joining tables

There are two tables and using linq query to get records. From second table, there can be multiple rows corresponding to first table with date timestamp... based on below query, I am getting all records, but is there a way we can get the row from second table which has latest timestamp ?
Table Parent
ID Name
1 M
2 N
3 O
4 P
5 Q
Table Child
Id fkID DateTime
1 2 01/12/2021 09:12:20
2 2 01/12/2021 09:13:20
3 2 01/12/2021 09:14:20
4 2 01/12/2021 09:15:20
5 2 01/12/2021 **09:16:20**
Linq query:
from p in Parent
join c in Child on p.id equals c.fkId into cJoin
from cJoin in cJoin.DefaultIfEmpty()
select new TempResponse
{
Id = p.Id,
Name = p.Name,
Date = c.Date
}
I am getting 10 records using above query but just need 5 records i.e. from child table instead of all 5 records, we need a record that has latest time stamp
**expected output**
1 M
2 N 01/12/2021 09:16:20
this record is 5'th record from child table because this one has latest date time stamp
( latest record )
3 O
4 P
5 Q
Is there any way we can use group by and get the record that has latest time stamp from second table ?
Assuming you have defined navigation properties for the FK, I would use a query like;
dbContext.Child.Where(c => c.Date == c.Parent.Child.Max(c2 => c2.Date))
I believe you can use:
var ans = from p in Parent
join cmax in (
from c in Child
group c by c.fkId into cg
select cg.OrderByDescending(c => c.Date).FirstOrDefault())
on p.Id equals cmax.fkId into cJoin
from c in cJoin.DefaultIfEmpty()
select new TempResponse {
Id = p.Id,
Name = p.Name,
Date = c != null ? c.Date : null
};
Note that the order of results seems to vary on SQL Server unless you add another orderby clause before the select to force an order.

Filtering Country information from Geographic data by Linq

I have such a table in my database:
Id City Country
==============================
1 A X
2 B X
3 C X
4 D X
5 M Y
6 N Y
7 O Y
8 P Y
9 U Z
10 V Z
I want to get Countries with first (minimum) Id from the table. The result set should be like:
Id Country
=================
1 X
5 Y
9 Z
I can get this result with SQL as :
SELECT
MIN(Id) AS Id,
Country
FROM
AllCityList
GROUP BY
Country
ORDER BY
Country ASC
But when I add this view to EntityFramework since MIN() hides PrimaryKey column (Id) I get an error. Hence, I want to convert this query to Linq. How can I write this query in Linq?
You can use GroupBy with Min. The below query groups the data based on Country and selects the Min Id.
return AllCityList.GroupBy(d => d.Country).Select(d =>
{
var first = d.First();
return new { Id = d.Min(x => x.Id), Country = first.Country};
});
Check this dotnetfiddle which demos the scenario.
Also, with using of Min it will make sure to fetch the minimum Id in case the column in not a clustered index.

How to get closest smallest number using linq C#

I have a sql table like this,
SomeDouble SomeInt
1.00 121
1.50 124
2.00 200
2.50 321
and so on... up to 10,000 for SomeDouble
Now I can have a decimal number anywhere between 0.0 to 10,000.00 and I need to find the correct row for it. For example if number is 1.12 then I want it to return 121.
1.49 should return 121, 1.50 should return 124, 1.51 should return 124.
Trimmed version of what I am trying is,
var myValue = 1.12
var SomeInt = (from mainTable in table1
join table3 in table2 on mainTable.someId equals table3.someId
where table3.Column1 == Column1 && mainTable.SomeDouble >= myValue
select mainTable.SomeInt).FirstOrDefault();
but my output is 124. How can I change above to get me the closest smallest number then myValue ?
Because the SomeDouble values are integers and half-integers, you can round up myValue to the next multiple of 0.5:
var myValueToLookUp = Math.Ceiling(myValue * 2) / 2;
and then look up the value of SomeInt directly with mainTable.SomeDouble == myValueToLookUp to avoid any confusion or inefficiency with <= or >=.
In SQL, you can express the closest as:
select t.*
from t
order by abs(SomeDouble - 1.12)
fetch first 1 row only;
A more efficient method would narrow it down to two rows first:
select t.*
from ((select t.*
from t
where t <= 1.12
order by SomeDouble desc
fetch first 1 row only
) union all
((select t.*
from t
where t > 1.12
order by SomeDouble asc
fetch first 1 row only
)
) t
order by (SomeDouble - 1.12)
fetch first 1 row only;
Using Linq queries:
var above = (from mainTable in table1
join table3 in table2 on mainTable.someId equals table3.someId
where table3.Column1 == Column1 && mainTable.SomeDouble >= myValue
orderby mainTable.SomeDouble
select new {SomeInt = mainTable.SomeInt, SomeDouble = mainTable.SomeDouble}).FirstOrDefault();
var below = (from mainTable in table1
join table3 in table2 on mainTable.someId equals table3.someId
where table3.Column1 == Column1 && mainTable.SomeDouble < myValue
orderby mainTable.SomeDouble descending
select new {SomeInt = mainTable.SomeInt, SomeDouble = mainTable.SomeDouble}).FirstOrDefault();
int SomeInt;
if (above == null)
SomeInt = below.SomeInt;
else if (below == null)
SomeInt = above.SomeInt;
else if (Math.Abs(below.SomeDouble - myValue) <= Math.Abs(above.SomeDouble - myValue))
SomeInt = below.SomeInt;
else
SomeInt = above.SomeInt;
Here's the linq extension method to order the records by absolute difference of SomeDouble, then by SomeInt to get the smallest first for 2 or more matches, and then we get the first one. It looks like both columns exist on main table, so I'm guessing we can limit that first then join whatever you want to it.
mainTable.OrderBy(x => Math.Abs(x.SomeDouble - myValue)).ThenBy(x => x.SomeInt).First()
If you can do it in SQL, then
SELECT COALESCE(MAX(SomeInt), 0)
FROM DoubleToInt
WHERE SomeDouble <= 1.12

LINQ to SQL Join orderby

i am new to LINQ and joins, so Please forgive me if I am asking it wrong.
I have two tables
Table1
id name date
1 Mike 20-10-15
2 John 21-10-15
3 Sam 23-10-15
Table2
id name date
1 Ashle 19-10-15
2 Lily 21-10-15
3 Jeni 22-10-15
4 April 23-10-15
I need 5 records using Joins and should be orderby Date, most recent records.
Can you guys help me, I really need to figure out how Joins works with orderby.
Thanks
EDIT:
They are two different tables so no foreign key, so I think I can't use Join, so so far what I have done is like this
var combinddata = (from t1 in db.Table1
select t1.id)
.Concat(from t2 in db.Table2
select t2.id);
I don't know how to get only 5 records how to compare records from both tables on DateTime base.
Output should be
Sam
April
Jeni
John
Lily
You can concatenate equal anonymous types from different tables. If you also select the dates, you can sort by them, in descending order, and take the first 5 records:
Table1.Select (t1 =>
new
{
Id = t1.Id,
Name = t1.Name,
Date = t1.Date
}
).Concat(
Table2.Select (t2 =>
new
{
Id = t2.Id,
Name = t2.Name,
Date = t2.Date
}
))
.OrderByDescending (x => x.Date).Take(5)
Note that this gives precedence to items in Table1. If item 5 and 6 in the concatenated result are on the same date, but from Table1 and Table2, respectively, you only get the item from Table1.
If you want, you can select only the names from this result, but I assume that your output only shows the intended order of record, not the exact expected result.
var query =
from Table1 in table1
join Table2 in table2 on table1.id equals table2.id
orderby table1.date ascending
select table1.date;
Try this way
var combinddata = (from t1 in db.Table1
select t1.Name)
.Concat(from t2 in db.Table2
select t2.Name).OrderByDescending(x => x.date).Take(5);

LINQ to SQL - CASE statement with subquery

I am having trouble trying to represent the below SQL (which returns the results I want) in LINQ:
select
case r.CategoryID
when 2 then
case r.PrimaryRecord
when 1 then r.RecordID
else (select RecordID from Record where RecordGroupID = r.RecordGroupID and PrimaryRecord = 1)
end
else
r.RecordID
end
as RecordID
, r.FooID
from Record r
where
r.FooID = 3
Each row in the Record table has a unique RecordID. Multiple RecordID's could be associated with a RecordGroupID for CategoryID 2, but only one of them will have the PrimaryRecord field value of 1.
Given the below table of data, my desired output is RecordID = 1, FooID = 3, i.e. the RecordID for the given RecordGroupID that is the PrimaryRecord, but the FooID for the given row that matches my Where clause.
RecordID RecordGroupID PrimaryRecord CategoryID FooID
1 1 1 2 1
2 1 0 2 1
3 1 0 2 3
I appreciate the SQL itself probably isn't the most efficient SQL in the world but it was the best I could come up with.
If anyone could help me create the LINQ statement to represent this query that would be great.
I think you don't really need the case in the original query. Try something like:
var matchingRecords = from r in Records
where r.FooId = fooId && r.CategoryId == catId && r.RecordGroupId == groupId
join r2 in Records on r.RecordGroupId == r2.RecordGroupId && r.CategoryId == r2.CategoryId && r2.PrimaryRecord
select r2;
Edit: added CategoryId in join, assuming RecordGroupId is only unique inside a category.

Categories

Resources