get all the latest entries from table linq - c#

I have two tables like below: (date format : mm/dd/yyyy)
Parameter master table:
Id Parameter
1 ST
2 GP
3 Interest
4 CC
And Second TaxValue table :
Date ParameterId Value
1/1/2017 1 4
2/1/2017 1 4.5
1/15/2017 2 15
3/20/2017 2 20
3/21/2017 3 18
4/28/2017 3 20
1/1/2017 4 10
I want to write a linq query to get all the latest parameters values from the date specified.
Desired Result: (if I want to get latest entries for today)
Date Parameter Value
2/1/2017 ST 4.5
3/20/2017 GP 20
4/28/2017 Interest 20
1/1/2017 CC 10
Please help!!

User OrderByDescending
var result = from n in table
group n by n.Value into g
select g.OrderByDescending(t=>t.Date).FirstOrDefault();

You can do a join on the latest TaxValue record like this:
var qry = (from pm in parameterMaster
from tax in taxValue.Where(t => t.ParameterId == pm.Id)
.OrderByDescending(t => t.Date)
.Take(1)
.DefaultIfEmpty()
select new {
date = tax.Date,
parameter = pm.Name,
value = tax.Value
});
var results = qry.ToList();

You can use this query: (I tested it and it worked properly)
using (testEntities db = new testEntities())
{
var res = from element in
(from p in db.Parameters
join t in db.TaxValues on p.Id equals t.ParameterId
select new { Date = t.Date, Parameter = p.Parameter1, Value = t.Value, ParameterId = t.ParameterId }).ToList()
group element by element.ParameterId
into groups
select groups.OrderBy(p => p.Value).Last();
}
Result

Related

Join with last record of details table

Please consider these two tables in my database:
Header:
Id Name
-------------------------------
1 London
2 Berlin
3 Paris
and Details:
Id HeaderId Amount YearMonth
--------------------------------------------------------------------
1 1 1000 2010-01
2 1 2000 2010-05
3 2 3000 2015-04
4 2 2700 2017-12
5 2 4500 2016-10
6 2 7000 2011-09
7 1 3000 2009-05
I want Header records with related Last Details record. For example:
HeaderId HeaderName Amount
----------------------------------------------------
1 London 2000
2 Berlin 2700
3 Paris Null
I wrote this query for Inner Join version (But I want Outer Join version):
from h in Header
join d in Details
on h.Id equals d.HeaderId
select new
{
HeaderId = h.Id,
HeaderName = h.Name,
Amount = (Details.Where(k=>k.HeaderId == h.Id).OrderBy(m=>m.YearMonth).LastOrDefault() == null ? null : Details.Where(k=>k.HeaderId == h.Id).OrderBy(m=>m.YearMonth).LastOrDefault().Amount,
}
and I got this error:
System.NotSupportedException: LINQ to Entities does not recognize the method 'Details.LastOrDefault()Details' method, and this method cannot be translated into a store expression.
How can I get above result?
thanks
This query should return desired result:
from h in Header
from d in Details.Where(d => d.HeaderId == h.Id)
.OrderByDescending(d => d.YearMonth)
.Take(1)
.DefaultIfEmpty()
select new
{
HeaderId = h.Id,
HeaderName = h.Name,
Amount = d.Amount
}
You should change your code as :
Amount = Details.Where(k=>k.HeaderId == h.Id).OrderByDescending(m => m.YearMonth).FirstOrDefault(o=>o.Amount);

Linq Query using GroupBy() and Sum() and Returning Values not Grouped

When attempting to write a linq query to Group some Data and Sum it, i'm receiving the following error:
CS1061 'CM_Records' does not contain a definition for 'Sum' and no
extension method 'Sum' accepting a first argument of type 'CM_Records'
could be found
var results = (from r in CM_Records
join sub in CM_Records on r.Id equals sub.Id
select new {R = r, S = sub}
into joined
group joined by new
{
label = joined.R.ServiceDateTime.Value.Month + "/" + joined.R.ServiceDateTime.Value.Day + "/" + joined.R.ServiceDateTime.Value.Year,
joined.R.CategoryId
}
into grouped
select grouped.Select(g =>
new
{
grouped.Key.label,
grouped.Key.CategoryId,
Value = g.S.Sum(x => int32.Parse(x.Value)), //This is the line that fails
//Value = g.S.Value, //Uncomment this line and comment the line above to get the following output.
ServiceTime = Convert.ToDateTime(g.S.ServiceDateTime).ToShortTimeString()
})
)
.SelectMany(x => x);
I understand that Sum Requires the object to be IQueryable, just not sure how to accomplish that in this this query without breaking something else.
Keep in mind that this query is being set to variable and then used in conjunction to generate a JSON object in C#.
Current Output without SUM:
Label Cat. Value ServiceTime
1/1/2017 439960 121 9:00 AM
1/1/2017 439960 131 5:00 PM
1/1/2017 439960 213 11:45 AM
1/1/2017 439960 210 10:20 AM
1/1/2017 439961 143 9:30 AM
1/1/2017 439994 92 9:30 AM
1/1/2019 439989 0 7:00 PM
1/1/2020 439968 172 7:00 PM
1/10/2018 439968 124 7:00 PM
1/10/2018 439969 120 7:00 PM
I need the above results to be Grouped by the Label Column and the Values summed.
Try this query:
var results = (from r in CM_Records
join sub in CM_Records on r.Id equals sub.Id
select new {R = r, S = sub}
into joined
group joined by new
{
label = joined.R.ServiceDateTime.Value.Month + "/" + joined.R.ServiceDateTime.Value.Day + "/" + joined.R.ServiceDateTime.Value.Year,
joined.R.CategoryId
}
into grouped
select new
{
grouped.Key.label,
grouped.Key.CategoryId,
Value = grouped.ToList().Select(x => x.S.value).Sum()
}).ToList();
Including the ServiceTime doesn't make much sense, unless you decide to select the max, min or something like that.

GroupBy Multiple Tables Using Foreign Key

I have two tables, and I calculate Post Views from Views table using ViewDate column and then I want to get PostTItle using .GroupBy for Entity Framework using foreign key PostID.
Posts table:
PostID PostTitle
--------------------
1 post one
2 post two
3 post three
4 post four
5 post five
6 post six
Views table:
ViewID ViewDate PostID
---------------------------------------
1 2015 07 17 19:00:00 1
2 2015 07 17 20:00:00 1
3 2015 07 17 21:00:00 2
4 2015 07 18 19:00:00 2
5 2015 07 19 19:00:00 2
6 2015 07 21 19:00:00 1
7 2015 07 23 19:00:00 2
so far this is what I have done
return _db.ObjectSet.Where(p => DateTime.Now >= EntityFunctions.AddDays(p.ViewDate, -14))
.GroupBy(y => y.PostID, y => y.ViewDate, (ID, Date) => new ExampleViewModel
{
Post_ID = ID,
View_Date = Date.Count()
}).OrderByDescending(z => z.View_Date).Take(5);
but using this solution I can only assign Post_ID and View_Date to ExampleViewModel, How can I get the PostTitle using the foreign key?
Note: I am trying to get most viewed (Hot) Posts in last 14 days
Please help
Expected Output:
Title:post one, Id:1, Views:3
Title:post two, Id:2, Views:4
One solution could be applying a join between those entities and include the PostTitle in the fields you want to group:
var query= (from v in db.Views
join p in db.Posts on v.PostID equals p.Id
where DbFunctions.DiffDays(v.ViewDate,DateTime.Now)<=14
group new{v,p} by new {v.PostID, p.PostTitle, v.ViewDate} into g
let count=g.Count()
orderby count descending
select new{ Post_ID=g.Key.PostID, View_Date=count, Title= g.Key.PostTitle}
).Take(5);
As you can see, I'm using DbFunction class instead EntityFunction. The DbFunctions class was introduced in Entity Framework 6 and it is shipped separately from the .NET Framework. For any new applications using versions of EF starting with 6.0, you should use the DbFunctions class. Anyway, if you don't want to use now that class, you could also use the EntityFunctions.DiffDays method.
Now if both entities are related:
public class Post
{
public int ID{get;set;}
// ...
public virtual ICollection<View> Views{get;set;}
}
public class View
{
public int ID{get;set;}
public int PostID{get;set;}
// ...
public virtual Post Post{get;set;}
}
You could also do this:
var query= (from v in db.Views
where DbFunctions.DiffDays(v.ViewDate,DateTime.Now)<=14
group v by new {v.PostID, v.ViewDate} into g
let count=g.Count()
orderby count descending
select new{ Post_ID=g.Key.PostID, View_Date=count, Title= g.First().Post.PostTitle}
).Take(5);
Update 1
To avoid use EntityFunctions class you can subtract 14 days to the current date and compare directly both dates in your query:
var date = DateTime.Now.AddDays(-14);
var query= (from v in db.Views
join p in db.Posts on v.PostID equals p.Id
where v.ViewDate>=date
group new{v,p} by new {v.PostID, p.PostTitle, v.ViewDate} into g
let count=g.Count()
orderby count descending
select new{ Post_ID=g.Key.PostID, View_Date=count, Title= g.Key.PostTitle}
).Take(5);
Update 2
That is because you're grouping by date. To obtain the result you're expecting you need to remove that field from the elements you are grouping:
var query= (from v in db.Views
join p in db.Posts on v.PostID equals p.Id
where v.ViewDate>=date
group new{v,p} by new {v.PostID, p.PostTitle} into g
let count=g.Count()
orderby count descending
select new{ Post_ID=g.Key.PostID, View_Date=count, Title= g.Key.PostTitle}
).Take(5);
If you have the Posts table on your context you can retrieve it from there by the PostId:
return _db.ObjectSet.Where(p => DateTime.Now >= EntityFunctions.AddDays(p.ViewDate, -14))
.GroupBy(y => y.PostID, y => y.ViewDate, (ID, Date) => new ExampleViewModel
{
Post_ID = ID,
View_Date = Date.Count(),
Title = _db.Posts.Find(ID).PostTitle
}).OrderByDescending(z => z.View_Date).Take(5);

Efficient way of finding multiple dates per ID

I'm trying to query my MsSQL Express database to find all CompanyID's which have multiple dates associated - when I say multiple dates, I must point out they need to be over different days.
EG
ID UkDate CompanyId
1 01/01/2015 16
2 01/01/2015 16
3 03/01/2015 18
4 05/01/2015 19
5 06/01/2015 20
6 08/01/2015 20
In the example above, only the rows with ComapnyID 20 would be returned because it occurred multiple times and those times were over dates (note that although companyId 16 has multiple entries, but both entries are the same date).
I'm not sure how to write the query for this using Linq. My object is already IQueryable<T> but, I'm not sure how to perform the query without executing the code, and then 'finishing off' the query.
I'm not near Visual Studio but the code would be (please forgive typing errors, this is from memory)
//First, grab unique CompanyIds as this removes those who didn't visit multiple times
var uniqueIds = (from d in this._database.MyTable
select companyId).Distinct();
//This is the problem because on each iteration I'm re-querying the database!
foreach(var id in uniqueIds)
{
var result = (from d in this._database.MyTable.OrderBy(a=>a.UkDate)
where d.CompanyId==id
select d);
//check for nulls
if (result.First(a=>a.UkDate.Day) != result.Last(a => a.UkDate.Day)
{
this.AllResultsList.AddRange(results);
}
}
Whilst it works without error I don't feel the code is correct - it feels like a hack and unefficient but this was my best effort. Is there a way I could reduce the number of database requests I make and achieve the same result
It would be something along the lines of
var results = myTable.GroupBy(x => x.CompanyID)
.Where(g => g.GroupBy(g2 => g2.UkDate).Count()>1)
.Select(g => g.Key);
Live example (albeit with LinqToObjects, but the query should work against a database just fine): http://rextester.com/FPHI53553
var results = (from o in this._database.MyTable
group o by o.CompanyId into grouped
where (grouped.Max(s => s.UKDate) - grouped.Min(s => s.UKDate)).TotalDays > 0
select grouped.Key);
Edit (by OP)
Final result:
var results = (from o in this._database.MyTable
group o by o.CompanyId into grouped
where (Convert.ToDateTime(grouped.Max(s => s.UKDate)) - Convert.ToDateTime(grouped.Min(s => s.UKDate))).TotalDays > 0
from l in myTable
where l.CompanyID == grouped.Key
select l).ToList();
A little different version:
var result = (from o in this._database.MyTable
group o by o.CompanyId into grouped
select new {
grouped.Key,
Count = grouped.Select(c => c.UkDate).Distinct().Count()
} into filter
where filter.Count > 1
join a in this._database.MyTable on filter.Key equals a.CompanyID
select new { a.CompanyID, a.UkDate}
).ToList();
You can also try this if you want the company id and a count of the different dates:
from c in dataTable
group c by c.CompanyId into grouped
let count = grouped.Select(x => x.UkDate).Distinct().Count()
where count > 1
select new { CompanyId = grouped.Key, Count = count }

.net linq entity framework groupby

I have a db table with columns like
DaysInTrade, PercentGain
i want a sum of PercentGain grouped by DaysInTrade
so:
DaysInTrade,PercentGain
1, 5
1,6
2,4
Would give me:
DaysInTrade, Sum
1, 11
2,4
I was not able to get intellisense working in the "select new" part unless I used something like Sum or Select. the DIT column below shows up blank no matter if I do ts.DaysInTrade, or gts.DaysInTrade
var partialQuery = (from ts in context.TradeSnapshots
group ts by ts.DaysInTrade
into gts
select
new
{
profit = gts.Sum(s => s.PercentGain),
DIT = gts.Select(ts=>ts.DaysInTrade)
});
dataGridViewTradeSnapshots.DataSource = partialQuery.ToList();
You want to use the key on the grouping. See the documentation on IGrouping<TKey,TElement>
var partialQuery = (from ts in context.TradeSnapshots
group ts by ts.DaysInTrade
into gts
select
new
{
profit = gts.Sum(s => s.PercentGain),
DIT = gts.Key
});
dataGridViewTradeSnapshots.DataSource = partialQuery.ToList();

Categories

Resources