Linq Select causes InvalidCastException - c#

var courses = db.Courses.Select(course => new Model.Course() {
Dates = db.Dates
.Where(date => date.CourseID == course.ID)
.Select(date => date._Date.ToString())
.ToList()
});
return courses.ToList();
The return call causes System.InvalidCastException. If I remove Dates, there is no error.
Here's Course class:
public class Course {
public List<string> Dates { get; set; }
}
Screenshot from VS:

The .ToString() on your _Date column could be causing the InvalidCastException. Linq to SQL is trying to convert your _Date into a string using ToString() which does not exist in SQL. You will need to simply grab the date as is from SQL and convert to string in memory.
Try this:
// Grab from db list of courses and their dates.
// Put dates in a List of DateTime, but you can also use DateTime2.
// Note that courses will be an IQueryable.
var courses = db.Courses.Select(course => new List<DateTime> {
Dates = db.Dates
.Where(date => date.CourseID == course.ID)
.Select(date => date._Date).ToList()
});
// Extract data from SQL by calling our IQueryable's ToList() of method. This puts the data as a List in memory.
// Using the List.Select() method, convert dates to strings. This will return an IEnumerable.
// Convert the resulting IEnumerable back to a List.
return courses
.ToList()
.Select(course => new Model.Course
{
// Here, you are using the .NET Framework's DateTime.ToString()
// So you can use any formatting options available with that.
Dates = course.Dates.Select(date => date.ToString()).ToList()
})
.ToList();

You didn't show the complete model but I think you should rather be joining those two tables with a join and not a where similar to this:
var courses =
db.Courses
.Join(
db.Dates,
c => c.ID,
d => d.CourseID,
(c, d) => new
{
Course = c,
Dates = d
}
).ToList();

Related

Convert to IEnumerable<DateTime> result of LINQ Query

I have a linq Query
var tListOfDates = tList.GroupBy(g => g.dateOfSlot)
.Select(s => new {s.Key.Value });
dateOfSlot is a DateTime value
How can I convert tListOfDates to IEnumerable<DateTime>
I've tried top cast the result, but it doesn't work.
You should drop anonymous class new {s.Key.Value } (you don't want it but DateTime):
var tListOfDates = tList
.GroupBy(g => g.dateOfSlot)
.Select(s => s.Key.Value);
It seems that dateOfSlot is of type DateTime?, not DateTime since you put s.Key.Value, not s.Key; if my guess is right you can put it as
var tListOfDates = tList
.Where(item => item.dateOfSlot.HasValue)
.Select(item => item.dateOfSlot.Value)
.Distinct();
A proposition,you take all dates and get the unique date by Distinct
var tListOfDates = tList.Select(g => g.dateOfSlot).Distinct();
I Solved with
IEnumerable<DateTime> tListOfDates = tList.Where(w => w.dateOfSlot.HasValue).Select(g => g.dateOfSlot).Distinct().ToArray().Cast<DateTime>();
May be there is something more that needed and the query can be simplified.
So you have an object tlist, which implements IEnumerable<MySlot>. We don't know a lot of MySlot, yet we know that every MySlot object has a DateTime property DateOfSlot.
The first part of your LINQ statement groups all MySlots in your tlist into groups of MySlots where every MySlot in the group has equal DateOfSlot:
tList.GroupBy(mySlot => mySlot.dateOfSlot)
Every group has a Key which contains this common DateOfSlot. So the Key is d DateTime object
The second part projects every group into one element:
.Select(group => new {group.Key.Value });
group.Key is a DateTime. The problem is that a Datetime does not have a property Value. Are you sure that DateOfSlot is a DateTime?
It's not entirely certain what you want.
I have an IEnumerable<MySlot> in tList, and I want all used DateOfSlot values in this list
var allUsedDateOfSlotValues = tList.Select(mySlot => mySlot.DateOfSlot);
But now I have duplicates, I don't want duplicates!
var allDistinctUsedDateOfSlotValues = tList
.Select(mySlot => mySlot.DateOfSlot)
.Distinct();
This will have the same result as your code:
var result = tList.GroupBy(mySlot => mySlot.DateOfSlot)
// result: groups of mySlots with same DateOfSlot
.Select(group => group.Key)
// result: distinct values of DateOfSlot

Group by some columns depending on values in Entity Framework

I have the following simple statement in my Entity Framework code:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault());
It simply finds the latest Notification based on a group by with conversationId and select latest. Easy.
However, this is ONLY what I want if c.NotificationType == NotificationType.AppMessage. If the column is different than AppMessage (c.NotificationType <> NotificationType.AppMessage), I just want the column. What I truly Want to write is a magical statement such as:
query = query
.Where(c => (c.NotificationType <> NotificationType.AppMessage)
|| ((c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault()));
But this doesn't make sense because the GroupBy/Select is based on the first where statement.
How do I solve this?
The simplest way is to compose UNION ALL query using Concat at the end of your original query:
query = query
.Where(c => c.NotificationType == NotificationType.AppMessage)
.GroupBy(c => c.ConversationId)
.Select(d => d.OrderByDescending(p => p.DateCreated).FirstOrDefault())
.Concat(query.Where(c => c.NotificationType != NotificationType.AppMessage));
public class EntityClass
{
public int NotificationType { get; set; }
public int ConversationId { get; set; }
public DateTime Created { get; set; }
public static EntityClass GetLastNotification(int convId)
{
var list = new List<EntityClass>(); // Fill the values
list = list
.GroupBy(i => i.ConversationId) // Group by ConversationId.
.ToDictionary(i => i.Key, n => n.ToList()) // Create dictionary.
.Where(i => i.Key == convId) // Filter by ConversationId.
.SelectMany(i => i.Value) // Project multiple lists to ONLY one list.
.ToList(); // Create list.
// Now, you can filter it:
// 0 - NotificationType.AppMessage
// I didn't get what exactly you want to filter there, but this should give you an idea.
var lastNotification = list.OrderByDescending(i => i.Created).FirstOrDefault(i => i.NotificationType == 0);
return lastNotification;
}
}
you filter your list with "GroupBy" based on ConversationId. Next, create a dictionary from the result and make only one list (SelectMany). Then, you already have one list where should be only records with ConversationId you want.
Last part is for filtering this list - you wanted to last notification with certain NotificationType. Should be working :)

How to Select then OrderBy using LINQ?

I am trying to sort the contents of a CSV file according to their dates with the following code from a question a posted earlier:
private class CSVEntry
{
public DateTime Date { get; set; }
public string Grp { get; set; }
}
...
List<CSVEntry> csvList = new List<CSVEntry>();
csvList.Add(new CSVEntry() { Date = DateTime.ParseExact(col[7], "dd/MM/yyyy", null), Grp = col[9] });
var results = csvList.OrderBy(x => x.Date); // An error occurs at "Date".
...
But I got this error:
'string' does not contain a definition for 'Date' and no extension method 'Date' accepting a first argument of type 'string' could be found.
What I want the output to be is the strings from other columns but sorted chronologically. When I tried using this code to display the dates:
var results = csvList.Where(x => x.Grp == "DEFAULT").OrderBy(x => x.Date);
It works perfectly with the output as dates sorted chronologically. However, this time I don't want to display the dates. I want to display the strings from other columns like I've mentioned above. I tried using
var results = csvList.Select(x => x.Grp).OrderBy(x => x.Date);
but got the same error as well. Where have I gone wrong? I am new to LINQ and unfamiliar with List<T> and IEnumerable<T> and this is my first time using them.
Add Select after your order the records, Like below
var results = csvList
.Where(x => x.Grp == "DEFAULT")
.OrderBy(x => x.Date)
.Select(x => x.Grp);
Reddy's answer should work, but I will explain it for you, so you understand why it does.
When you use the Select(x => x.Grp) Statement you don't have a IEnumerable<CSVEntry> anymore. You only have a IEnumerable with all Grp-Entrys from your csvList. So When you try to order them by Date by adding a OrderBy(x => x.Date) Statement, Linq doesn't know the Date Property, because in this Statement x is only a string, not a CsvEntry.
In Reddys Answer, he first filter all Entrys by Grp == "DEFAULT". After that he has a IEnumerable<CsvEntry> left, so he can Order them by x.Date. After that, again, he has a IEnumerable<CsvEntry> left. Only after the last Statement, the Select(x => x.Grp) Statement, he has a IEnumerable<string> left.
Hope that helps :)

String Format on LINQ controller statement MVC

im having problems using String format on my LINQ but only on my Controller, using it on my view work well, so how can i change my LINQ to not give me an error in the Controller.
This is my LINQ
foreach (var item in db.Pos.Where(r => r.Fecha.Day.ToString() == "2").Select(g => new { Pdv = g.Pdv, Total = g.Total })
.GroupBy(l => l.Pdv).Select(z => new { Pdv = z.Key, Total = String.Format("{0:$#,##0.00;($#,##0.00);Zero}",Decimal.Round(z.Sum(l => l.Total), 0) }))
{
listadepuntos.Add(item.ToString());
}
var grupoPdv = new SelectList(listadepuntos.ToList());
ViewBag.GroupS = grupoPdv;
what i want is that the data of ViewBag.GroupS gets ',' each 3 digits , like for hundreds, thousands and millions right now i get the date plain without format.
what can i do?
You can call AsEnumerable extension method after your group by to execute your Select method using Linq to Objects instead Linq to Entities:
.GroupBy(l => l.Pdv)
.AsEnumerable()// Add this
.Select(z => new { Pdv = z.Key, Total = String.Format("{0:$#,##0.00;($#,##0.00);Zero}",Decimal.Round(z.Sum(l => l.Total), 0) })
The issue is because your Linq provider doesn't know how to convert your method calls to a proper expression tree, which later need to be translated to a SQL statement. There is a few string methods that are currently supported (you will find them in this link), String.Format is not one of them. In case of Decimal.Round which is either supported, you could use System.Math.Round instead.

LINQ projection combining date and list

I have a list of objects containg value and date of transaction.
DateTime Date { get ; set; }
double Value { get; set; }
I want to get the new grouped object which will contain date of transaction and list of values for this particular day.
I can retrieve both list and date but i dont know how to use projection to cast them into new object.
var res1 = ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => p.Value)
.ToList();
DateTime res2 = ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => p.Date)
.FirstOrDefault();
There might have been some confusion around I will post pictures to clarify
I have something like this in ExpenseList set of date and value
I want one Date and Collection of Values
To group all of the values for a particular day you'll want to use GroupBy
var groups = ExpenseList.GroupBy(expense => expense.Date,
expense => expense.Value);
ExpenseList.Where(p => p.Date == Convert.ToDateTime("01-12-2013"))
.Select(p => new MyObject {Date = p.Date, Value = p.Value})
.ToList();
Replace MyObject for the actual type you have defined.

Categories

Resources