Linq sort date when it's a shortdatestring - c#

I'm trying to sort by date with linq when I already have a date brought back from linq that I converted to a shortdatestring:
var NOVs = from n in db.CT_NOVs
join i in db.CT_Inspectors on n.ARBInspectorID equals i.CTInspectorID
join v in db.CT_ViolationTypes on n.ViolationTypeID equals v.ViolationTypeID
join t in db.CT_Tanks on n.CargoTankID equals t.CargoTankID
join c in db.CT_Companies on t.CompanyID equals c.CompanyID
select new
{
n.NOVID,
n.NOVNumber,
NOVDate = n.NOVDate.Value.ToShortDateString(),
ARBInspectorFirstName = i.FirstName,
ARBInspectorLastName = i.LastName,
v.ViolationName,
t.CargoTankID,
c.CompanyName
};
Here is where I try to sort by the date, but it's giving me an error since I converted the datetime into a shortdatestring:
if (column == "NOVDate")
{
if (sortDirection == "ascending")
NOVs = NOVs.OrderBy(b => Convert.ToDateTime(b.NOVDate));
else
NOVs = NOVs.OrderByDescending(b => Convert.ToDateTime(b.NOVDate));
}
Any clue on how to sort by NOVDate?

Why don't you leave it as a full DateTime object and convert it to a ShortDateString right before you display it to the user? I usually try to leave the objects in their native format and convert them to display to the user at the last second. That'll help with separating your data layer from your presentation layer too, i.e., let the presentation layer decide how to display the date to the user; your data layer shouldn't really care.
From the comments:
Since you're using a <asp:BoundField> element with your GridView, you can use the DataFormatString property to have the grid view automatically format it.
It looks like using DataFormatString="{0:d}" should do the trick. (thanks Gromer!)

You can use the the "orderby" clause before selecting the elements.
Check this link: http://msdn.microsoft.com/en-us/library/bb383982.aspx

you sort it first then display it as you want:
var NOVs = from n in db.CT_NOVs
join i in db.CT_Inspectors on n.ARBInspectorID equals i.CTInspectorID
join v in db.CT_ViolationTypes on n.ViolationTypeID equals v.ViolationTypeID
join t in db.CT_Tanks on n.CargoTankID equals t.CargoTankID
join c in db.CT_Companies on t.CompanyID equals c.CompanyID
orderby n.NOVDate.Value
select new
{
n.NOVID,
n.NOVNumber,
NOVDate = n.NOVDate.Value.ToShortDateString(),
ARBInspectorFirstName = i.FirstName,
ARBInspectorLastName = i.LastName,
v.ViolationName,
t.CargoTankID,
c.CompanyName
};
then you can do this:
if (column == "NOVDate")
{
if (sortDirection != "ascending")
NOVs = NOVs.Reverse();
}

Related

Only include in where condition if date is not low date(01/01/0001)

I have a query that has a where condition to check and find addresses that were added after a certain date. The date field is not required so I want Date field in where condition to be only considered if it is not 1/1/0001.
dtmDate is the parameter that is being passed
Query
from b in _context.customer
join d in _context.Address on b.id equals d.Id
join e in _context.units on d.Id equals e.Id
where (req.dtmDate.Year != 1 && d.DateAdded >= req.dtmDate)
select new modelAddress
{
address= d.address
}
But this is not working. It is not returning any rows
I'd leverage the fact that LINQ queries are not executed when you write them, so you can add clauses conditionally after you've created a base query:
var query = from b in _context.customer
join d in _context.Address on b.id equals d.Id
join e in _context.units on d.Id equals e.Id;
if(req.dtmDate.Year != 1)
query = query.Where(d.DateAdded >= req.dtmDate);
var result = query.Select(
new modelAddress
{
address= d.address
}
);
I prefer this because I've previously run into issues, particularly with EF LINQ queries when the Where clause contains something that evaluates to true locally with in the code, rather than as something the DB will evaluate. It seems to work out better when "wildcarding" DB queries, to use a pattern of "if x is true then add-another-where-clause" rather than saying "where(local-value-of-x-equals-local-constant OR some-db-data-value-equals-y)"
If I understand you correctly, you have a DateTime object called req.dtmDate that may be set to a default value, and you want to return all items where the item's DateAdded field is greater than req.dtmDate, unless req.dtmDate is 1/1/0001, in which case all records should be returned.
If that's the case, I think you could just modify your existing code to:
where (req.dtmDate.Year == 1 || d.DateAdded >= req.dtmDate)

Access data from indirect child table using LInq

I have following table in my database and im accessing them through EF.
TestPack { id, name, type }
Sheets{ id, tp_id, date, rev }
Spool { id, sheet_id, date, rev, fabricated, installed }
which means a test pack has 1-M sheets and each sheet has 1-M spools. I want to get count of total Spools in the Test Pack, and count of spools that are fabricated, count of spools that are installed.
How do I get that through Linq query?
if I understand you right,you would like to have something like this
(from tp in ctx.TestPack
join st in ctx.Sheets on st.tp_id equals tp.id
join sl in ctx.Spool on sl.steet_id equals st.id
where tp.id == testPackId //you can change or delete this condition
select new {
Total = sl.Count() ,
FabricatedSpools = sl.Count(x=>x.fabricated == true),
InstalledSpools = sl.Count(x=>x.installed == true)
}).FisrtOrDefault();
Or maybe
(from tp in ctx.TestPack
join st in ctx.Sheets on st.tp_id equals tp.id
join sl in ctx.Spool on sl.steet_id equals st.id
where tp.id == testPackId //you can change or delete this condition
select new {
Total = sl.Count() ,
FabricatedSpools = (from s in sl
where s.fabricated == true
select s.Count()),
InstalledSpools = (from i in sl
where i.installed== true
select i.Count()),
}).FisrtOrDefault();
Not sure what you exact models are like but see below.
var testPackID = 2;//assuming
//assuming your DbContext is ctx;
var totalSpools = ctx.Spools.Count(x => x.Sheets.tp_id == testPackID);
var fabricatedSpools = ctx.Spools.Count(x => x.Sheets.tp_id == testPackID && x.fabricated);
var installedSpools = ctx.Spools.Count(x => x.Sheets.tp_id == testPackID && x.installed);
Sample data and query
I had generated the queries in SQL Server and hope you can do in LINQ. if you want specifically in LINQ let me know.
And can you please clarify whether you want result in 3 or all the 3 results in one.
Hope this helps.
Thank you.

convert trans-sql to LINQ LEFT JOIN and Where Clause

How would you convert this trans-sql to LINQ?
I've tried it with the DefaultIfEmpty() but it seems to not be working for me.
Any help is appreciated.
SELECT s.Status
FROM EducationModule M
LEFT JOIN EducationModuleStatus S ON M.CourseID = S.CourseID
AND M.ModuleID = S.ModuleID
AND S.StudentID = '1506'
WHERE M.courseid = 2
Thanks in advance.
Joining on multiple columns in Linq to SQL is a little different.
You have to take advantage of anonymous types and compose a type for the multiple columns you wish to compare against, and under the sheet this will generate the type of join you are looking for.
var abcd = from tl in db.EducationModule
join s in db.EducationModuleStatus
on new { t1.CourseID, t1.ModuleID } equals new {s.CourseID, s.ModuleID}
into tl_s
where tl.CourseID == 2 AND s.StudentID == '1506'
from s in tl_s.DefaultIfEmpty()
select new
{
Status = s.Status
};

C# SQL/Linq/Entity Framework calculating column totals for multiple columns from large data source

Sorry to bother you, however I'm having issues converting my SQL Query into C# Entity Framework.
My SQL query is as follows:
SELECT CAST(ROUND(sum(size/rate), 0) AS INT) s,
CAST(ROUND(sum(PL/rate), 0) AS INT) PL
FROM [bs].[b] b
join [bs].[s] s on b.id = s.b_id
join [bs].[o] o on s.o_id = o.id
join [bs].[a] a on o.a_id = a.id
join [fs].[f] f on b.f_id = f.id
where f.r_date
between '2013-05-01 00:00:00.000'
and '2013-05-31 00:00:00.000'
and s.deleted_at is NULL
and b.group_id = '0'
and (o.a_id = 50 or o.a_id = 52)
I have in turn managed to get all the joins done and where statement in place (a.k.a. 'The Easy Bit') however I just cannot find a way to get those sums for the column totals to work.
This is what I have in place so far:
var GroupSk = (from Bs in sb.b
join S in sb.s on Bs.id equals S.b_id
join O in sb.o on S.o_id equals O.id
join A in sb.a on O.a_id equals A.id
join Fs in sb.vw_f on Bs.f_id equals Fs.f_id
where Fs.r_date >= t_FromDate && Fs.r_date <= t_ToDate
where S.deleted_at == null
where Bs.group_id == 0
where O.a_id == 50 || O.a_id == 52
select new {
As you can see, it's everything up until the SUM part of the query.
This query can return anywhere from 1-150000 rows, and I need a way to ensure that the column totals I get back are returned in a timely manner.
I had originally planned on using a ForEach loop but had trouble implementing it (along with the fact that it'll probably take a LONG time if a larger number of rows are returned).
I'm aware there are a few 'sum column total' questions out there, however they don't deal with multiple tables and multiple column outputs. They also appear to be limited to 2 or 3 columns total, whereas my tables far exceed that.
Any & all help would be greatly appreciated.
It's a bit of a hack, but it works. The trick is to make one group containing all items and then do the sums over the group:
var GroupSk = (from Bs in sb.b
join S in sb.s on Bs.id equals S.b_id
join O in sb.o on S.o_id equals O.id
join A in sb.a on O.a_id equals A.id
join Fs in sb.vw_f on Bs.f_id equals Fs.f_id
where Fs.r_date >= t_FromDate && Fs.r_date <= t_ToDate
where S.deleted_at == null
where Bs.group_id == 0
where O.a_id == 50 || O.a_id == 52
select new { r1 = ??.size / ??.rate, r2 = ??.PL / ??.rate })
.GroupBy(x => 0)
.Select(g => new {
R1 = g.Sum(x => x.r1),
R2 = g.Sum(x => x.r2)
});
I put ?? marks where I didn't know the origin of the properties, so you'll have to substitute the right variable names there. (Bs, S, O, A, Fs).
This will translate into one SQL query, so all the processing is done by the database engine and only the small result object is transferred over the wire.

Show 3 result from each element in group by

I am working on a system for handling meter reading.
I want to produce a output where the system displays all the meters belonging to the customer and for each meter, the three last readings.
So far, I have to followering code:
var lastMeterReading = from meeters in metermodel.Meeters
join reading in metermodel.Readings on meeters.MeterNumber equals reading.MeterNumber
where (maalers.CustNo == 6085574)
orderby reading.Date descending
group meeters by new { meeters.MeterNumber, reading.Consumption, reading.Date } into result
select new
{
Consumption = result.Key.Consumption, No = result.Key.MeterNumber, Date = result.Key.Date
};
Now, it shows all the meters belonging to the customer. If I put a .take(3), it only shows the first 3 results.
Thx!
Daniel
I think what you need is to put the .Take(3) in the right place.
In you case you probably did result.Take(3) but this means take the first three groups (with all their elements).
Below is an attempt to show what I mean, however, I suppose you will need to fix it in the last part, as I don't have data to test it on, and as such I'm not sure if what I'm trying to access is accessible at that point. But I hope you get what I mean.
var lastMeterReading = (from meeters in metermodel.Meeters
join reading in metermodel.Readings on meeters.MeterNumber equals reading.MeterNumber
where (maalers.CustNo == 6085574)
orderby reading.Date descending
group meeters by new { meeters.MeterNumber, reading.Consumption, reading.Date } into result
from m in result
select new {Key = m.Key, Info = result.OrderByDescending(r => r.Date).Take(3)})
.Select(r => new
{ Consumption = r.Consumption, No = r.MeterNumber, Date = r.Date });
Try this:
var lastMeterReading = from meeters in metermodel.Meeters
join reading in metermodel.Readings on meeters.MeterNumber equals reading.MeterNumber
where (maalers.CustNo == 6085574)
orderby reading.Date descending
group meeters by new { meeters.MeterNumber, reading.Consumption, reading.Date } into result
from m in result.Take(3)
select new
{
Consumption = m.Consumption, No = m.MeterNumber, Date = m.Date
};
You only want to group by MeterNumber. The way you're doing the grouping right now, you'll get a new group for every unique MeterNumber-Consumption-Date combination.
You can also simplify your query using LINQ's GroupJoin operator. In query syntax you use the "join..on..into" pattern:
from meter in meterModel.Meters
where (meter.CustNo == 6085574)
join reading in meterModel.Readings
on meter.MeterNumber equals reading.MeterNumber
into meterGroup
select meterGroup.OrderByDescending(r => r.Date).Take(3);
Or using dot notation:
meterModel.Meters
.Where(x => x.CustNo == 6085574)
.GroupJoin(
meterModel.Readings,
meter => meter.MeterNumber,
reading => reading.MeterNumber,
(meter,readings) => readings.OrderByDescending(r => r.Date).Take(3))
;

Categories

Resources