C# LINQ replacing nulls with meaningful string - c#

From the list
class Delivery
{
public string ProductCode
{
get;
set;
}
public DateTime? OrderedDate
{
get;
set;
}
public DateTime? DeliveryDate
{
get;
set;
}
public Delivery(string pcode, DateTime? orddate, DateTime? deldate)
{
ProductCode = pcode;
OrderedDate = orddate;
DeliveryDate = deldate;
}
}
List<Delivery> DeliveryList = new List<Delivery>();
DeliveryList.Add(new Delivery("P001",new DateTime(2009,01,27),null));
DeliveryList.Add(new Delivery("P007",new DateTime(2009,05,17),null));
DeliveryList.Add(new Delivery("P031", new DateTime(2008, 03, 15),
new DateTime(2008,04 ,22)));
DeliveryList.Add(new Delivery("P011",new DateTime(2009,01,27),
new DateTime(2009,02,12)));
DeliveryList.Add(new Delivery("P041",new DateTime(2009,01,27),null));
DeliveryList.Add(new Delivery("P051", new DateTime(2009, 01, 27),
new DateTime(2009, 02, 12)));
DeliveryList.Add(new Delivery("P501",new DateTime(2009,01,27),null));
DeliveryList.Add(new Delivery("P801",new DateTime(2009,01,27),null));
var query = DeliveryList.OrderBy(p => p.DeliveryDate);
For Report purpose ,During LINQ execution,What is the way to replace null values (Based on Delivery Date) with
message "Yet to be delivered" (DateTime is value type).

var result = DeliveryList.Select(x => new
{
ProductCode = x.ProductCode,
OrderedDate = x.OrderedDate,
DeliveryDate = x.DeliveryDate.HasValue
? x.DeliveryDate.Value.ToString() : "Yet to be delivered"
}).OrderBy(p => p.DeliveryDate).ToArray();

I'm not 100% sure what your asking but it sounds like you want to convert DeliverList into a collection of strings indicating when they were delivered. In the case of a null DeliveryDate though you want the string "Yet to be delivered". If so try the following.
var dates = DeliveryList
.Select(x => x.DeliverDate
? x.DeliverDate.Value.ToString
: "Yet to be delivered");

Darin's solution is neat and I'd go with it. As an alternate consideration...
if you want to keep the type as with the solution above an anonymous type is created and the delivery date will probably end up as a string.
List<Delivery> query = (from d in DeliveryList
select new Delivery
(
d.ProductCode,
d.OrderedDate,
d.DeliveryDate ?? DateTime.Now
)).OrderBy(p=>p.DeliveryDate).ToList();
if you had an empty constructor in your Delivery class you could do something like
List<Delivery> query2 = (from d in DeliveryList
select new Delivery
{
DeliveryDate = d.DeliveryDate ?? DateTime.Now,
OrderedDate = d.OrderedDate,
ProductCode = d.ProductCode
}).OrderBy(p=>p.DeliveryDate).ToList();
The one thing you'd have to do then, is have a meaninful replacement for your DeliveryDate if it's null. I don't think DateTime.Now would be useful and now you'd be stuck with a DateTime field. The advantage obviously, is that you're sitting with a List object which is strongly cast. And helps I guess if later on you do put logic into your contructor.

Related

How to get maximum Time group by id c#

From the client API I get list of data. I have following code, this is a sample code, just need to create sample list to show client data.
class Program
{
static void Main(string[] args)
{
List<Author> authors = new List<Author>
{
new Author { Id = "100", Status = "Time (02:15 PM)" , Value = "A" , Test = "B" },
new Author { Id = "101", Status = "Time (02:16 PM)" , Value = "A" , Test = "B"},
new Author { Id = "100", Status = "Time (02:10 PM)" , Value = "A" , Test = "B"},
new Author { Id = "100", Status = "Time (11:15 AM)" , Value = "A" , Test = "B"},
new Author { Id = "101", Status = "Time (03:40 PM)" , Value = "A" , Test = "B"},
new Author { Id = "100", Status = "Time (02:15 AM)" , Value = "A" , Test = "B"}
};
var aa = authors.ToList();
}
}
public class Author
{
public string Id { get; set; }
public string Status { get; set; }
public string Value { get; set; }
public string Test { get; set; }
}
Here I need to get distinct Id with their maximum Status by its time value.
From the output I should need to get this.
Id = 100, its maximum Status is : Time (02:15 PM)
Id = 101, its maximum Status is : Time (03:40 PM)
How can I do this, its looks something mad, but I need to do this. how can I do this
Updated :
DateTime dt1 = DateTime.Now ;
List<Author> authors = new List<Author>
{
new Author { Id = "100", Test = "A", dateTime = dt1.AddMinutes(-5) },
new Author { Id = "101", Test = "K", dateTime = dt1.AddMinutes(-8) },
new Author { Id = "100", Test = "C", dateTime = dt1.AddMinutes(-6) },
new Author { Id = "100", Test = "D" , dateTime = dt1.AddMinutes(-18)},
new Author { Id = "101", Status = "G" , dateTime = dt1.AddMinutes(-6)},
new Author { Id = "100", Status = "Q" , dateTime = dt1.AddMinutes(-3)}
};
Updated my question, I added
I added another field called datetime for the ease of the Get max value. Then how can I get maximum datetime for each Id
Output need there two records data,
Id = "100", Status = "Q" , dateTime = dt1.AddMinutes(-3)
Id = "101", Status = "G" , dateTime = dt1.AddMinutes(-6)
I didn't try but maybe you can split (03:40 PM) part in all statuses and with CultureInfo.InvariantCulture's help you can convert this string to datetime. Then with linq's help you can try something like this:
var list = authors
.OrderBy(x => x.Id)
.ThenByDescending(x => x.Status)
.GroupBy(x => x.Id)
.Select(y=> y.FirstOrDefault())
.ToList();
authors.GroupBy(x => int.Parse(x.Id)).Select(x => x.OrderByDescending(y=> DateTime.Parse(y.Status.Substring(6, 8))
).FirstOrDefault());
Apparently Status is a string, but you want to interpret it as a DateTime.
If you can, add a property to your Author:
class Author
{
...
public Datetime StatusTime => // use property Status to extract the Time
}
I assume I don't have to write how you get the Time from the Status string. If that is a challenge for you this will be a nice exercise for you.
If you can't change class Author, consider to create an extension method, so that you can use it, as if it is a method in class Author.
If you are not familiar with extension methods, see Extension methods demystified
public static class AuthorExtensions
{
public static DateTime GetStatusTime(this Author author)
{
// TODO: remove the "Time = ( " part and use DateTime.Parse,
}
}
Usage:
Author author = ...
DateTime time = author.GetStatusTime();
Once you've got a method like this, the LINQ will be easy: make groups of Authors with same Id, and from every Author in one group, take the Author with the highest value for StatusTime:
IEnumerable<Author> authors = ...
// Make groups of Authors with same Id:
var result = authors.GroupBy(author => author.Id,
// parameter resultSelector, from every Id, and authors with this Id,
// select the author with the highest StatusTime:
(authorId, authorsWithThisId) => authorWithThisId
.OrderBy(author => author.GetStatusTime())
.FirstOrDefault());
It is a bit of a waste, to order the ten Authors in a group if you will be using only the first Author. If performance is an issue, consider to use Aggregate:
(authorId, authorsWithThisId) => authorWithThisId.Aggregate(
(selectedAuthor, nextAuthor) => (nextAuthor.GetStatusTime() > selectedAuthor.GetStatusTime()) ?
nextAuthor : selectedAuthor);
This will still translate the Status into StatusTime several times, so the optimal method:
var result = authors.Select(author => new
{
Id = author.Id,
StatusTime = author.GetStatusTime(),
})
.GroupBy(author => author.Id)
.Select(authorGroup => authorGroup.Aggregate(
(x, y) => (x.StatusTime > y.StatusTime) ? x, y);

Date format not working in MVC with Entity Framework?

I'm trying to get some data to format in the ShortDateTime format of "MM/dd/yyyy" but everything I'm trying is not working.
I have the following EF below and the field I'm specifically looking at is the ExpireDate. When I try to use a DateTime.Parse around the field I get an error cannot convert from 'System.DateTime?" to 'string'. Without the DateTime.Parse then the date displays as 3/15/2017 12:00:00 AM.
I tried using Data Annotations on the Model as well but that doesn't seem to work either.
Any suggestions?
EF query
data = (from e in ctx.clock_emp_excep_hist
join g in ctx.clock_group on e.group_id equals g.group_id
join emp in ctx.employee on e.emp_id equals emp.emp_id
where e.group_id == 4
select new
{
UpdateDate = e.create_date,
UpdateType = e.add_delete_ind,
GroupId = e.group_id,
GroupName = g.group_name,
Reason = e.reason,
ExpireDate = e.expiration_date,
UpdateEmployeeId = e.emp_id,
UpdateFirstName = emp.emp_firstname,
UpdateLastName = emp.emp_lastname
}).Select(e => new EmployeeExceptionLog {
UpdateDate = e.UpdateDate,
UpdateType = e.UpdateType == "A" ? "Add" : "Delete",
GroupId = e.GroupId,
GroupName = e.GroupName,
Reason = e.Reason,
ExpireDate = DateTime.Parse(e.ExpireDate),
UpdateEmployeeId = e.UpdateEmployeeId,
UpdateFirstName = e.UpdateFirstName,
UpdateLastName = e.UpdateLastName
}).ToList();
}
Property in class
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode=true)]
public DateTime? ExpireDate { get; set; }
More info:
This is how I'm displaying the data in the View.
#foreach (var item in Model.AuditLogs)
{
<tr class="#(item.UpdateType == "Delete" ? "danger" : "")">
<td>#item.UpdateDate</td>
<td>#item.UpdateType</td>
<td>#item.Reason</td>
<td>#item.ExpireDate</td>
<td>#item.UpdateEmployeeId - #item.UpdateFirstName #item.UpdateLastName</td>
</tr>
}
The DataType in the Oracle Database is DateTime?.
public DateTime? ExpireDate { get; set; }
Its nullable date so you can have Null value for ExpireDate.
"cannot convert from 'System.DateTime?" to 'string'"
ExpireDate = DateTime.Parse(e.ExpireDate),
DateTime.Parse takes string as a parameter.
i would change this to
ExpireDate = ((e.ExpireDate != null) ? (DateTime)e.ExpireDate : "SOME DEFAULT DATE"),
Also in View you can display using ToShortDateString() if your model property is dateTime.
<td>#item.ExpireDate.ToShortDateString()</td>
here is more info about DateTime.
You can't parse nullable DateTime.
To convert nullable DateTime into a formatted string :
ExpireDate != null ? ExpireDate.Value.ToString("MM/dd/yyyy") : "ERROR";
Update your query into this:
data = (from e in ctx.clock_emp_excep_hist
join g in ctx.clock_group on e.group_id equals g.group_id
join emp in ctx.employee on e.emp_id equals emp.emp_id
where e.group_id == 4
select new
{
UpdateDate = e.create_date,
UpdateType = e.add_delete_ind,
GroupId = e.group_id,
GroupName = g.group_name,
Reason = e.reason,
ExpireDate = e.expiration_date,
UpdateEmployeeId = e.emp_id,
UpdateFirstName = emp.emp_firstname,
UpdateLastName = emp.emp_lastname
}).Select(e => new EmployeeExceptionLog {
UpdateDate = e.UpdateDate,
UpdateType = e.UpdateType == "A" ? "Add" : "Delete",
GroupId = e.GroupId,
GroupName = e.GroupName,
Reason = e.Reason,
ExpireDate = ExpireDate != null ? ExpireDate.Value.ToString("MM/dd/yyyy") : "ERROR",
UpdateEmployeeId = e.UpdateEmployeeId,
UpdateFirstName = e.UpdateFirstName,
UpdateLastName = e.UpdateLastName
}).ToList();
}

Get the List of max and min dates from a LIST

I am getting distinct Company Name through this query
List<string> listCieId = new List<string>(from l in LstAdvancePaymentRep select l.CieDesc.Trim()).Distinct().ToList();
What i want to do is get the Minimum Dated Maximum Date for all the companies in listCieId
List<DateTime> listCieId2 = new List<DateTime>(from l in LstAdvancePaymentRep where l.CieDesc.Trim().Distinct() select l.CtcDtStart.Value).Min().ToList();
List<DateTime> listCieId3 = new List<DateTime>(from l in LstAdvancePaymentRep where l.CieDesc.Trim().Distinct select l.CtcDtEnd.Value).Max().ToList();
I am new to such queries haven't used them before
EDIT: I am using Distinct to get a the distinct company names as there is a repetition in the LstAdvancePaymentRep
EDIT: Tried this out
List<DateTime> lstDatesCtcStartDate = new List<DateTime>(
from l in LstAdvancePaymentRep where l.CieDesc.Trim().Equals(lblCieName.Text.Trim()) select l.CtcDtStart.Value.Date
);
How do i find the minimum date in the LIST lstDatesCtcStartDate
Try:
var minDate = lstDatesCtcStartDate.Min();
Or, if your company object had a Name and a Date property and there where multiple of each company and you wanted a list of each distinct company with the smallest date then:
class Company
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
var companies = new List<Company>();
var companiesWithMinDate = companies.GroupBy(c => c.Name).Select(g => new { Name = g.Key, Date = g.Min(c => c.Date) });

Running total based on each record in a LINQ query for MVC ASP.net

I'm running into two issues:
I tried assigning a ROW_NUMBER to my SQL view and do a running sum based on the row number (and therefore get the sums based on each record), but the resulting performance hit was quite noticeable.
I know how to do this in T-SQL for dates:
The RunningTotal column in this SQL statement is exactly what I need (itemized sums).
But it takes very long to execute.
UPDATE 2 Here is how I created my second view.
CREATE VIEW [dbo].[vCI_UNIONALL_ROW] AS
SELECT ROW_NUMBER() OVER(ORDER BY EffChkDt DESC) AS [Row]
,*
FROM vCI_UNIONALL
GO
My model:
public class UnionAllModel
{
public int? InvoiceNumber { get; set; }
[DataType(DataType.Currency)]
public Decimal? Amount { get; set; }
[DataType(DataType.DateTime)]
public DateTime? EffChkDt { get; set; }
[omitted for clarity]
}
Here's my LINQ query so far:
using (var db = new PLOGITENS01Entities())
{
var rvUnionAll = (from u in db.vCI_UNIONALL
orderby u.EffChkDt ascending
select new UnionAllModel()
{
InvoiceNumber = u.InvoiceNumber,
Date = u.Date,
AccountNumber = u.AccountNumber,
ClientName = u.ClientName,
Amount = u.Amount,
InAmount = u.InAmount,
OutAmount = u.OutAmount,
ClientRiskAdjs = u.ClientRiskAdjs,
SpecificAdjs = u.SpecificAdjs,
EffChkDt = u.EffChkDt,
PayStatus = u.PayStatus,
Type = u.Type
})
.ToList();
return View(new GridModel(rvUnionAll));
}
you can try creating the running sum adding the values to a local variable:
int runningSum = 0;
var rvUnionAll = (from u in db.vCI_UNIONALL.AsEnumerable()
orderby u.EffChkDt ascending
select new UnionAllModel()
{
InvoiceNumber = u.InvoiceNumber,
Date = u.Date,
AccountNumber = u.AccountNumber,
ClientName = u.ClientName,
Amount = u.Amount,
InAmount = u.InAmount,
OutAmount = u.OutAmount,
ClientRiskAdjs = u.ClientRiskAdjs,
SpecificAdjs = u.SpecificAdjs,
EffChkDt = u.EffChkDt,
PayStatus = u.PayStatus,
Type = u.Type,
RunningSum = runningSum += u.Amount
})
.ToList();

change date to all objects in the list and update

I am trying to change date to all workouts in the list, the other properties are working fine, its only when I change Date i get problem. I have tried different trouble shooting, but none have worked. I have tried with using updatedWorkout.Date as workoutStart = out of range. If I use old.Date, then, how can I add the new date with 7days a part ?
Maybe there is a better way to do this?
Here's my method:
private int UpdateForAllWorkouts(IWorkoutCommand updatedWorkout)
{
try
{ // get schedule
var schedule = _scheduleRepository.GetIncludeWorkouts(updatedWorkout.ScheduleId);
// get workouts within the schedule by schedule id
var workout = schedule.Workouts.FirstOrDefault(w => w.Id == updatedWorkout.Id);
for (var workoutStart = workout.Date; workoutStart <= schedule.ToDate; workoutStart = workoutStart.AddDays(7))
{
// get specdfic workout by workout id and start time
var old = schedule.Workouts.Single(w => w.Date == workoutStart && w.StartTime == workout.StartTime);
var tmp = new Model.Workout
{
Id = old.Id,
CourseId = updatedWorkout.CourseId,
InstructorId = updatedWorkout.InstructorId,
Date = //<---problem
StartTime = updatedWorkout.StartTime,
EndTime = updatedWorkout.EndTime,
ScheduleId = updatedWorkout.ScheduleId,
WeekOffSet = updatedWorkout.WeekOffSet.Days
};
}
return updatedWorkout.Id;
}
catch (Exception ex)
{
throw new Exception("");
}
}
thx for helping!
I think you can use a loop for 7.
like this :
var workoutStart = workout.Date;
while(true){
if(workoutStart <= schedule.ToDate){
// Do something
}else{
break;
}
workoutStart = workoutStart.AddDays(7);
}
Please consider to check the value of our DateTime properties.Their values could be less than your SQL server allow for datetime field.
What is the Date value of updatedWorkOut object before you assign "tmp" object ?
Is your "old" object null or what is the value of date ?
your code seems to be ok. the problem underlies the value of DateTime properties and fields.

Categories

Resources