Linq statement distinct not working on dates - c#

I've been looking all over stackoverflow.com and the Interwebz to find out how to use Linq with Distinct(), but I'm not having any luck with my situation.
What I'm trying to do is show a list of dates (Aug 2015, July 2015, etc) with each date showing just once.
What happens is that the months are duplicated because you can publish a new blog post more than once in a month. I thought using Distinct would help, but it seems like it's not doing anything. When I try adding GroupBy(), my OrderByDescending stops working, and I'm not seasoned enough to simply turn this into an IList, which I've seen in a couple other examples.
BlogRepeater.DataSource = _PostRepository.GetAll(ConfigurationManager.GetSiteID())
.Where(x => x.DatePublished != null && x.DatePublished >= DateTime.Now.AddYears(-1))
.Distinct().OrderByDescending(x => x.DatePublished)
.Select(x => x.DatePublished.Value.Date);
What is the best way to be doing this?
I've tried taking pieces from other examples, to no avail. Thanks in advance.
UPDATE: Thanks for the help! Here is working code in hopes it can help someone else in the future.
Code Behind:
BlogRepeater.DataSource =
_PostRepository
.GetAll(ConfigurationManager.GetSiteID())
.Where(x => x.DatePublished != null && x.DatePublished >= DateTime.Now.AddYears(-1) && x.Status == "Published")
.Select(x => x.DatePublished.Value.ToString("MMM yyyy"))
.Distinct()
.OrderBy(x => x);
BlogRepeater.DataBind();
Front End:
<%#(Container.DataItem)%>

If your DatePublished field contains DateTime values with different times, the .Distinct() will not behave how you expect it to, because those values are essentially different.
If you want distinct dates, not date/times, then you can move the last .Select before the .Distinct():
BlogRepeater.DataSource =
_PostRepository
.GetAll(ConfigurationManager.GetSiteID())
.Where(x => x.DatePublished != null && x.DatePublished >= DateTime.Now.AddYears(-1))
.Select(x => x.DatePublished.Value.Date)
.Distinct()
.OrderByDescending(x => x);
If you want to find the distinct months, not dates, then you have to change the
.Select(x => x.DatePublished.Value.Date)
line to
.Select(x => x.DatePublished.Value.ToString("MMM yyyy"))
Feel free to change the "MMM yyyy" format to anything else you find suitable.

Related

Getting today, past, and tomorrows list of appointments

I have a problem when it comes to getting dates and times to be displayed as a list on the view page of my application.
Example:
public IList<Appointment> GetTodaysAppointments()
{
DateTime today = DateTime.Now.Date;
return db.Appointments
.Where(e => e.StartDateTimeBooking == today)
.Include(e => e.Patient)
.ThenInclude(p => p.User)
.Include(e => e.Doctor)
.ThenInclude(d => d.User)
.OrderBy(d => d.StartDateTimeBooking)
.ToList();
}
This is my code and to save repeating code to get tomorrow and past appointments this would be the same outlook for the code.
I have tried implementing the operator "<". This works great for past appointments and will only display past appointments and nothing else.
The Issue: When I try to use "==" It will not display today's appointments or any appointment. However, If I use ">=", It will show today and upcoming appointments. This is great but I do not need it for tomorrow's appointments. I want tomorrow to be separate.
I did notice I am using DateTime which I do have Dates with time stored in my variable.
I know If I need to get today's appointments I want to do something like this:
StartDateTimeBooking >= YESTERDAY_MIDNIGHT && StartDateTimeBooking <= TODAY_MIDNIGHT
My Problem is my time is in 24 hours' time. What equation or code do I need today to ensure that: Today, past, and upcoming appointments will work?
I know I am very close to the solution but any help would be greatly appreciated.
UPDATE: Is this logic correct?
This gives me todays list of appointments:
.Where(e => e.StartDateTimeBooking >= today && e.StartDateTimeBooking < today.AddDays(1))
This gives me tomorrows list of appointments only:
Where(e => e.StartDateTimeBooking > today.AddDays(1) && e.StartDateTimeBooking < today.AddDays(2))
This gives me an upcoming list of appointments
.Where(e => e.StartDateTimeBooking >= today)
This gives me past appointments:
.Where(e => e.StartDateTimeBooking < today)
Because dates include times in the database, you need an in between filter on your date:
Assuming today is your date variable and represents a date at midnight (e.g. DateTime.Today):
.Where(e => e.StartDateTimeBooking >= today && e.StartDateTimeBooking < today.AddDays(1))
This creates the between filter you should need. It's midnight or after, but before tomorrow at midnight (AddDays(1)).

Dynamic Linq Search using NinjaNye.SearchExtensions

I use the great NinjaNye.SearchExtensions in c# core mvc. That works perfect but I would need dynamic search options. Is that possible? Or do I need several if else blocks?
I have this linq
return tmpIQueryable
.Where(c => data.Contains(c.id) && c.enddate > DateTime.Now.Date && c.startdate < untildate)
.Include(c => c.DataContainer)
.Search(x => x.title.ToLower(),
x => x.manu.ToLower(),
x => x.short.ToLower(),
x => x.long.ToLower(),
x => x.detail.ToLower())
.ContainingAll(searchlist)
I have boolean variables where to search in (user can choose in GUI with checkboxes where he want to search in) - search_in_title, search_in_manu, search_in_short, search_in_long, search_in_detail. How can I dynamic search in a field or not without in this case 5^2 if/else for different linq.
Thanks a lot
Ralf
You may add .Where clause multiple times:
if (searchInTitleChecked)
tmpIQueryable = tmpIQueryable.Where(r => r.Title.ToLower() == title);
if (searchInShortChecked)
tmpIQueryable = tmpIQueryable.Where(r => r.Short.ToLower() == short);
This is just example of Linq, but not NinjaNye.SearchExtensions. If it's not helpful, please ignore.
However you may try the same here:
if (searchInTitleChecked)
tmpIQueryable = tmpIQueryable.Search(x => x.title.ToLower());
if (searchInShortChecked)
tmpIQueryable = tmpIQueryable.Search(x => x.short.ToLower());
tmpIQueryable = tmpIQueryable.ContainingAll(searchlist);

Linq to SQL order by with Distinct

My Environment: ASP.net and C# in VS 2013 Express.
I have been through many similar SO articles trying to work this out. I am amateur with Linq to SQL queries and c# in general.
I'm trying to use Linq to SQL to get the top 5 most recent distinct values from a column, then add them to a list. My application is asp.net using c# and a .dbml file for data abstraction.
I've tried it many different ways. I either get non-distinct yet sorted list, or I get a distinct unsorted list. What I have so far is below
var Top5MFG = (from mfg in db.orders
where mfg.manufacturer.Length > 0 && mfg.customerid == "blahblahblahblahblah"<br />
select new {
manufacturer = mfg.manufacturer,
date = mfg.date_created
})
.Distinct()
.OrderByDescending(s => s.date);
I'm thinking my "Distinct" is looking at the "ID" column, and perhaps I need to tell it I want it to look at the "manufacturer" column, but I haven't worked out how / if it's possible to do that.
I could do this with ease by using a storedproc, but I'm really trying to do it with c# code directly if possible. This is my first post to SO, I hope I have put it together properly. Any help much appreciated.
Thanks
No the Distinct compares manufacturer and date pairs.If you want to get distinct records by manufacturer then I recommend DistinctBy method.It's in the MoreLINQ library.Since its a third library method it's not supported in linq to sql, you still can use it by fetching the records from DB and do the rest in memory
(from mfg in db.orders
where mfg.manufacturer.Length > 0 && mfg.customerid == "blahblahblahblahblah"
select new {
manufacturer = mfg.manufacturer,
date = mfg.date_created
})
.AsEnumerable()
.DistinctBy(x => x.manufacturer)
.OrderByDescending(s => s.date)
.Take(5);
I think you can use the GroupBy to do what you want.
var Top5MFG = db.orders
.Where (x => x.manufacturer.Length > 0 && x.customerid == "blahblahblahblahblah")
.GroupBy(mfg => mfg.manufacturer)
.Select(g => g.First())
.OrderByDescending(d => d.date_created );
.Take(5);
One way you can distinct by a certain field is to replace:
...
.Distinct()
...
with:
...
.GroupBy(x => x.manufacturer )
.Select(g => g.First())
...

Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.IEnumerable<xxx>>' to 'System.Collections.Generic.List<xxx>

I am getting the following error. I googled it for more than a day but I cant find the exact solution, Please help me Thank you
ERROR: Cannot implicitly convert type
System.Collections.Generic.List<System.Collections.Generic.IEnumerable<ADCO.eJMC.EntityDataModel.ShareholderUser>>
to
System.Collections.Generic.List<ADCO.eJMC.EntityDataModel.ShareholderUser>
I used the following code
List<ShareholderUser> list = new List<ShareholderUser>();
list = dataContext.EJMCShareholderApprovals
.Include(s => s.Shareholder.ShareholderUsers)
.Where(e => e.EJMCRequestId == requestId)
.Select(s => s.Shareholder.ShareholderUsers
.Where(x => x.AccessMode == true))
.ToList();
The problem is that at the moment, you're selecting a sequence of sequences - one sequence of ShareholderUser items for each Shareholder. If you just want a list of ShareholderUser items, you need to flatten the results. That's most easily done using SelectMany, which can actually replace your Select call in this case.
List<ShareholderUser> list = dataContext.EJMCShareholderApprovals
.Where(e => e.EJMCRequestId == requestId)
.SelectMany(s => s.Shareholder.ShareholderUsers)
.Where(x => x.AccessMode == true)
.ToList();
Note how breaking the query over multiple lines makes it much simpler to read, too. Also, there's no point in initializing the list variable to a new List<ShareholderUser> if you're then immediately going to give it a different value. I've also removed the Include call, as that was unnecessary - you're explicitly selecting Shareholder.ShareholderUsers in the query, so you don't need to include it.
This should do it?
var list = dataContext.EJMCShareholderApprovals
.Include(s => s.Shareholder.ShareholderUsers)
.Where(e => e.EJMCRequestId == requestId)
.Select(s => s.Shareholder.ShareholderUsers
.Where(x => x.AccessMode == true)).ToList();
though you are doing select on to ShareHolderUsers? Are you trying to get a list of ShareHolderUsers or a list of lists of ShareHolderUsers?
.Select(s => s.Shareholder.ShareholderUsers

Linq select with filtering not working

I'm trying to select one field last record in filtered database (this is different than last inserted record). I tried with following code in controller but instead of field value, i'm getting "true" or "false", depending on if there's results after filtering or not.
List<Pozicije> poz = new List<Pozicije>();
poz = db.Pozicijes.Where(p => p.grupa == grupa)
.OrderBy(p => p.sifra_pozicije).ToList();
string pos = poz.Select(p => p.sifra_pozicije.Contains(s)).LastOrDefault().ToString();
can someone point me how to get value i need instead?
Try this instead. I've combined both parts of your query into one.
var pos =
Convert.ToString(db.Pozicijes.Where(p => p.grupa == grupa
&& p.sifra_pozicije.Contains(s))
.OrderByDescending(p => p.sifra_pozicije)
.Select(p => p.sifra_pozicije)
.FirstOrDefault());
If it doesn't work, you may need to tell us what types s and sifra_pozicije are.
LastOrDefault is not supported with LINQ to Entities/LINQ TO SQL. You need to do OrderByDescending and then get First record. Like:
string pos = db.Pozicijes.Where(p => p.grupa == grupa && p.sifra_pozicije.Contains(s)))
.OrderByDescending(p=> p.sifra_pozicije)
.Select(r=> r.sifra_pozicije)
.First();

Categories