The point is that you cannot operate with members with the same freedom as with content without either loading all members to the memory or manually quering the db. Personally for me using examine index looks like the most righteous solution.
Could try a slightly different lamda expression from Jochen's one:
DateTime dob;
var members = Member.GetAllAsList().OrderBy(m => DateTime.TryParse(m.getProperty("DateOfBirth").Value.ToString(), out dob) ? dob : DateTime.MinValue).ToList();
If you actualy have a property called "DateOfBirth" on your members, then lmy guess is that sometimes the Value is null and then you get an error on the ToString().
Maybe you can try with a cast instead of a ToString, so something like :
DateTime dob; var members =Member.GetAllAsList().OrderBy(m =>DateTime.TryParse((string)m.getProperty("DateOfBirth").Value,out dob)? dob :DateTime.MinValue).ToList();
Thanks Michael. I have tried the code. but unfortunately I am still getting the same error message, that is "Object Reference not set to an instance of an object"
Could it be that "'DateOfBirth" is a wrong property alias (case sensitive), or that not all members have a DateOfBirth Property attached to them? I am asking this because the only location of error I can think of, is the fact that m.getProperty("DateOfBirth") would return null.
If this is the case, maybe the following will work:
DateTime dob; var members =Member.GetAllAsList().OrderBy(m =>DateTime.TryParse((m.getProperty("DateOfBirth") == null? string.Empty :(string)m.getProperty("DateOfBirth").Value),out dob)? dob :DateTime.MinValue).ToList();
Definitely give Michael's solution a try first... it looks like it would work to me!
Failing that, you could try a more sure-fire, but long-winded, way - loading up all the member's date-of-births into a dictionary, then sort that first:
public static List<Member> GetAllMembersOrderedByDateOfBirth()
{
var members = Member.GetAllAsList();
var dateOfBirths = new Dictionary<Member, DateTime>();
foreach (var member in members)
{
var property = member.getProperty("dateOfBirth");
if (property != null && property.Value != null)
{
DateTime dob;
if (DateTime.TryParse(property.Value.ToString(), out dob))
{
dateOfBirths.Add(member, dob);
}
}
}
return dateOfBirths.OrderBy(x => x.Value).Select(x => x.Key).ToList();
}
Thanks a lot for your response. In fact I have replaced the property alias with the correct one of my project. I have tried the code you proposed but it returns the following:
Unable to cast object of type 'System.DateTime' to type 'System.String'.
DateTime dob; var members =Member.GetAllAsList().OrderBy(m =>DateTime.TryParse((m.getProperty("DateOfBirth")==null?string.Empty: m.getProperty("DateOfBirth").Value),out dob)? dob :DateTime.MinValue).ToList();
DateTime dob; var members = Member.GetAllAsList().OrderBy(m =>DateTime.TryParse(((m.getProperty("DateOfBirth")==null || m.getProperty("DateOfBirth").Value==null)?string.Empty: m.getProperty("DateOfBirth").Value.ToString()),out dob)? dob :DateTime.MinValue).ToList();
Now, if that works, and assuming that all members have the property "DateOfBirth" (of whatever the correct alias might be), I think the following should also work, and is a little easier:
var members = Member.GetAllAsList().OrderBy(m =>(m.getProperty("DateOfBirth")==null || m.getProperty("DateOfBirth").Value==null)?DateTime.MinValue: m.getProperty("DateOfBirth").Value).ToList();
@Jochen From the last error posted by Aaeda, I think we can assume that the type of "m.getProperty("DateOfBirth").Value" is actually already a DateTime, so I think (not tested) that your proposition would generate a "type mismatch" error between string.Empty and m.getProperty("DateOfBirth").Value
Have you already tried to print out the values of the property, just to see what values are returned? My guess is that somehow the getProperty or getProperty.Value always returns null, and therefore you always get DateTime.MinValue as sort value, which ends up in no sorting.
I don't see why it would be so, but if you can printout the values to check, at least we can see if that is the problem, or if we have to look for something else.
Dim memberGroups As MemberGroup() = MemberGroup.GetAll
Dim newDate As Date
Dim dob As DateTime
For Each memberGroup In memberGroups
If memberGroup.Text = getMemberGroup Then
Dim members = Member.GetAllAsList().OrderBy(Function(m) If(DateTime.TryParse((If((m.getProperty("dateOfBirth") Is Nothing OrElse m.getProperty("dateOfBirth").Value Is Nothing), String.Empty, m.getProperty("dateOfBirth").Value.ToString())), dob), dob, DateTime.MinValue)).ToList()
However, there is no year in the DateOfBirth. If there is no year provided, the datetime.Parse method will fail and therefore will always return the DateTime.MinValue.
Yes that is fine, but that is a problem you have to deal with in the results, not in the sorting.
If you don't want to save the year in Umbraco, you can't sort them by age (only by month/day) and if you want to sort them by month/day, you can add a dummy year to your property when you want to convert it to a datetime:
var members =Member.GetAllAsList().OrderBy(m =>(m.getProperty("DateOfBirth")==null||m.getProperty("DateOfBirth").Value==null)?DateTime.MinValue:m.getProperty("DateOfBirth").Value + "/1900").ToList();
This will only work if you have stored your date in Umbraco like: "22/04", not when it is stored like "22 April".
If you mean it does not need to appear in the front-end, it's not a problem, you just need to use it in your sorting expression, but it will not appear in your front-end.
If you mean that the value of the DateOfBirth property should not contain the year, then you will run into the problem that Jocha mentioned. In that case, one solution for it would be to attach a dummy year in the TryParse method, so something like
m.getProperty("dateOfBirth").Value.ToString() + "2000" or "2000" + m.getProperty("dateOfBirth").Value.ToString()
Note that in that case, your order will not be applied on the year, so you might end up having someone appear on top of someone 20 years younger...
Also, if the format you mentionned, "23 April", is the format you will sort on, this will give strange behaviors, as "April" will come before "January".
In all cases of the actual content of the BirthOfDate property, if you want to have correct sorting, I would suggest transforming the value to a format yyyyMMdd.
Yea the problem is coming from the data which are as follows (taking the first 3 rows above):
DANIEL MAROT
20 April
JOSEPH ALEXIS HAREL
26 April
NICOLAS JOEL MILLIOT
13 April
The year is as follows: 1951, 1962 and 1965 respectively
So obviously the sorting is working, but the order I need has to be in terms of the date and month only. The data is actually been saved as : 20 apr 1951 in the database.
I don't think that the Value property returns a string, but well a DateTime, as I have previously made a suggestion of casting it to string, like you do here, and Aaeda got an "error casting DateTime to String" message.
But from what you say, I think Value.ToString().Substring(5) would do.
It's logic since the Value property probably returns an object.
So back to our expression, we'll get there eventually :-) : instead of sorting on dob, we sort back to a ToString("MMdd") version of it:
var members =Member.GetAllAsList().OrderBy(m =>(m.getProperty("DateOfBirth")==null||m.getProperty("DateOfBirth").Value==null)?String.Empty : ((DateTime)m.getProperty("DateOfBirth").Value).ToString("MMdd")).ToList();
Note that in case there is nothing I return string.Empty, which will put the items on top, so if you want them below, just put something else like "zzzz".
So, starting back from the last (only) version that did not generate an error :
Dim members = Member.GetAllAsList().OrderBy(Function(m) If(DateTime.TryParse((If((m.getProperty("dateOfBirth") Is Nothing OrElse m.getProperty("dateOfBirth").Value Is Nothing), String.Empty, m.getProperty("dateOfBirth").Value.ToString())), dob), dob, DateTime.MinValue)).ToList()
Instead of returning the dob or DataTime.MinValue as OrderBy value, there we should be able to do a proper ToString. So, I am almost sure this will work:
Dim members = Member.GetAllAsList().OrderBy(Function(m) If(DateTime.TryParse((If((m.getProperty("dateOfBirth") Is Nothing OrElse m.getProperty("dateOfBirth").Value Is Nothing), String.Empty, m.getProperty("dateOfBirth").Value.ToString())), dob), dob.ToString("MMdd"), String.Empty)).ToList()
Sort members by date of birth
Hi
I am using the members API and I wanted to retrieve the list of members ordered by their date of birth in ascending order.
can someone please advise how can this be done?
thanks
Hi. I don't know how much it would be relevant, but there's a recent thread with a seem-to-be similar problem:
http://our.umbraco.org/forum/developers/api-questions/30325-Filter-members-based-on-a-generic-propery
The point is that you cannot operate with members with the same freedom as with content without either loading all members to the memory or manually quering the db. Personally for me using examine index looks like the most righteous solution.
Hi,
this should do the trick:
List<Member> members = Member.GetAllAsList().ToList<Member>();
members = members.OrderBy<Member, DateTime>(x => Convert.ToDateTime(x.getProperty("DateOfBirth").Value)).ToList();
HI Jochen,
I tried it but getting this error even if every member has a date of birth.
"Conversion from string "" to type 'Date' is not valid."
Hi Fuji,
Could try a slightly different lamda expression from Jochen's one:
Curious how many members do you have?
Cheers, Lee.
Approx 300 members....
The Linq/lambda approach should be fine... for a moment I thought you were gonna say 1,000+ ... then I'd start to consider using Examine/Lucene.
Hi Lee
I have tried the solution you mentioned above and I am having the following error:
'Object Reference not set to an instance of an object'
Hello,
If you actualy have a property called "DateOfBirth" on your members, then lmy guess is that sometimes the Value is null and then you get an error on the ToString().
Maybe you can try with a cast instead of a ToString, so something like :
Hope this helps
Cheers,
Michael.
Hi
Thanks Michael. I have tried the code. but unfortunately I am still getting the same error message, that is "Object Reference not set to an instance of an object"
Regards
aaeda
Hi aaeda,
Could it be that "'DateOfBirth" is a wrong property alias (case sensitive), or that not all members have a DateOfBirth Property attached to them? I am asking this because the only location of error I can think of, is the fact that m.getProperty("DateOfBirth") would return null.
If this is the case, maybe the following will work:
Cheers,
Michael.
Hi aaeda,
Definitely give Michael's solution a try first... it looks like it would work to me!
Failing that, you could try a more sure-fire, but long-winded, way - loading up all the member's date-of-births into a dictionary, then sort that first:
Cheers, Lee.
Hi Michael
Thanks a lot for your response. In fact I have replaced the property alias with the correct one of my project. I have tried the code you proposed but it returns the following:
Unable to cast object of type 'System.DateTime' to type 'System.String'.
Regards
Aaeda
You could try this:
Hi Aaeda,
OK, so we're getting closer I guess :-)
I think the following should work now:
Now, if that works, and assuming that all members have the property "DateOfBirth" (of whatever the correct alias might be), I think the following should also work, and is a little easier:
Cheers,
Michael.
@Jochen From the last error posted by Aaeda, I think we can assume that the type of "m.getProperty("DateOfBirth").Value" is actually already a DateTime, so I think (not tested) that your proposition would generate a "type mismatch" error between string.Empty and m.getProperty("DateOfBirth").Value
Cheers,
Michael.
True,
Your second solution should be waterproof, otherwise I think there's someting wrong inside the member profile.
Yes,I think so too.
Let's see what feedback we get from Aaeda :-)
Cheers,
Michael.
Hi Michael
Great!! no error message now! But the dates are not in order! In fact the list is being ordered by First Name.
Regards
Aaeda
Are you sure that the DateOfBirth property is filled in correctly for all the members?
Did you replace "DateOfBirth" in my code by the correct property alias of your project?
@Michael : yes I replaced by the alias of my project
@Jochen: Yes everyone has got a date of birth
Hi Aaeda,
Could you please copy your code here?
From where you fetch the members, do the sorting and databing your members.
Hi Aaeda,
Have you already tried to print out the values of the property, just to see what values are returned? My guess is that somehow the getProperty or getProperty.Value always returns null, and therefore you always get DateTime.MinValue as sort value, which ends up in no sorting.
I don't see why it would be so, but if you can printout the values to check, at least we can see if that is the problem, or if we have to look for something else.
Cheers,
Michael.
@Jochen : Please find below the codes
Dim memberGroups As MemberGroup() = MemberGroup.GetAll
Dim newDate As Date
Dim dob As DateTime
For Each memberGroup In memberGroups
If memberGroup.Text = getMemberGroup Then
Dim members = Member.GetAllAsList().OrderBy(Function(m) If(DateTime.TryParse((If((m.getProperty("dateOfBirth") Is Nothing OrElse m.getProperty("dateOfBirth").Value Is Nothing), String.Empty, m.getProperty("dateOfBirth").Value.ToString())), dob), dob, DateTime.MinValue)).ToList()
For Each member In members
If member.Groups.ContainsKey(memberGroup.Id) Then
getMemberDetails = member.GetMemberFromLoginName(member.LoginName)
If getMemberDetails.getProperty("memberProfile").Value <> "" Then
lblmember.Text += "<div><img src=""" & getMemberDetails.getProperty("memberProfile").Value & """> </div>"
End If
lblmember.Text += "<div class=""compTit"">" & getMemberDetails.getProperty("firstName").Value + " " + getMemberDetails.getProperty("lastName").Value & "</div>"
lblmember.Text += "<div class=""compProm"">" & FormatDate(getMemberDetails.getProperty("dateOfBirth").Value) & "</span></div>"
End If
Next
End If
Next
@ Michael: Please find below the results:
DANIEL MAROT
20 April
JOSEPH ALEXIS HAREL
26 April
NICOLAS JOEL MILLIOT
13 April
BRAMBHANAND BEEKHARRY
22 April
JEAN NOEL ROLAND ROSE
19 April
LAVAL LEE TING FONG AH-POONG
21 April
TANIA MARIE
16 April
JEAN BURT FREDERIC ASSIRVADEN
19 April
MARIE GERALDINE LABONNE
13 April
SAPNA GOOGOOLYE
23 April
VIJYANI IRANAH
19 April
KURT LOUIS JONATHAN GRIMAUD
27 April
ANNELISE BOISSARD
22 April
Well, your code doesn't seem wrong to me.
However, there is no year in the DateOfBirth. If there is no year provided, the datetime.Parse method will fail and therefore will always return the DateTime.MinValue.
Maybe you can try to specify the date format in the ToString, to be sure the year comes out also.
In order to have an ascending order, I would suggest something like "yyyyMMdd".
So, instead of m.getProperty("dateOfBirth").Value.ToString(), use m.getProperty("dateOfBirth").Value.ToString("yyyyMMdd")
Cheers,
Michael.
In fact the year is only not being displayed as it is Date of Birth and the client does not want the year to appear.
Yes that is fine, but that is a problem you have to deal with in the results, not in the sorting.
If you don't want to save the year in Umbraco, you can't sort them by age (only by month/day) and if you want to sort them by month/day, you can add a dummy year to your property when you want to convert it to a datetime:
This will only work if you have stored your date in Umbraco like: "22/04", not when it is stored like "22 April".
Hi Aaeda,
If you mean it does not need to appear in the front-end, it's not a problem, you just need to use it in your sorting expression, but it will not appear in your front-end.
If you mean that the value of the DateOfBirth property should not contain the year, then you will run into the problem that Jocha mentioned. In that case, one solution for it would be to attach a dummy year in the TryParse method, so something like
m.getProperty("dateOfBirth").Value.ToString() + "2000" or "2000" + m.getProperty("dateOfBirth").Value.ToString()
Note that in that case, your order will not be applied on the year, so you might end up having someone appear on top of someone 20 years younger...
Also, if the format you mentionned, "23 April", is the format you will sort on, this will give strange behaviors, as "April" will come before "January".
In all cases of the actual content of the BirthOfDate property, if you want to have correct sorting, I would suggest transforming the value to a format yyyyMMdd.
Cheers,
Michael.
Yea the problem is coming from the data which are as follows (taking the first 3 rows above):
DANIEL MAROT
20 April
JOSEPH ALEXIS HAREL
26 April
NICOLAS JOEL MILLIOT
13 April
The year is as follows: 1951, 1962 and 1965 respectively
So obviously the sorting is working, but the order I need has to be in terms of the date and month only. The data is actually been saved as : 20 apr 1951 in the database.
Ah OK,
Then it is easy :-). Just use the "MMdd" formatting in your ToString:
m.getProperty("dateOfBirth").Value.ToString("MMdd")
Cheers,
Michael.
Hi, guys,
I can be wrong, but afaik, a datepicker data field always returns a date as a string of the sortable format (like "yyyy-MM-dd").
So, I guess that
should be enough to sort values by month/day.
Hi Rodion,
I don't think that the Value property returns a string, but well a DateTime, as I have previously made a suggestion of casting it to string, like you do here, and Aaeda got an "error casting DateTime to String" message.
But from what you say, I think Value.ToString().Substring(5) would do.
Cheers,
Michael.
Ok, then you need not Value.ToString().Substring(5) but Value.ToString("s").Substring(5) to ensure a proper format.
Hi Rodion, Michael
I have tried the Substring and got an error:
startIndex cannot be larger than length of string.
Parameter name: startIndex
I also tried m.getProperty("dateOfBirth").Value.ToString("MMdd") but also got an error : Input String not in the correct version
OK,
It's logic since the Value property probably returns an object.
So back to our expression, we'll get there eventually :-) : instead of sorting on dob, we sort back to a ToString("MMdd") version of it:
Note that in case there is nothing I return string.Empty, which will put the items on top, so if you want them below, just put something else like "zzzz".
Cheers,
Michael.
Hi Michael
thanks a lot for your replies. Still getting the same error message as once before:
Specified cast is not valid.
Aaarghh ;-)
Getting lost here!!
Can you tell me what is the actual output of m.getProperty("DateOfBirth").Value.ToString()?
I thought it was string, then DateTime, and now we get errors about integers...
So, if you can tell me the output of the ToString(), at least we will be sure about which type we are working with :-)
Cheers,
Michael.
yeahh! lost :(
The property if of type : DatePicker and it output values like: 1984-05-31
OK,
So, starting back from the last (only) version that did not generate an error :
Instead of returning the dob or DataTime.MinValue as OrderBy value, there we should be able to do a proper ToString. So, I am almost sure this will work:
Cheers,
Michael.
Hi Michael
Greatttt:) It works! Thanks a lot for your help and alos everyone else who participated !
Cheers
Aaeda
Aaaaahhhh, finally !!! ;-)
Can you maybe mark my previous post as solution, so that other people with similar issues might find it easily? Thanks!
Cheers,
Michael.
yeah finally :) I can't seem to find where I can mark the post as solution !
is working on a reply...