2013-02-27 1 views
4

Я хотел бы запросить у моих клиентов те, чьи дни рождения еще впереди.Запрос на предстоящие дни рождения

Я попробовал этот запрос, и это - конечно - не удалось умопомрачительно:

Addresses.Where(adr => adr.DateOfBirth != null && adr.DateOfBirth.Value > 
DateTime.Now).Take(15).ToList(); 

Конечно, это не может работать должным образом (если вы не родились в будущем), и я d хотел бы знать, как я могу запросить мой Nullable<DateTime> без года?

+6

Учитывая, что * каждый * живой имеет наступающий день рождения в какой-то момент, как далеко вы хотите, чтобы он ушел? Месяц? Конец года? –

+0

'Take (15)' - только в ближайшие 15 дней рождения.Конец года может быть проблемой, когда я запускаю запрос 31 декабря. – SeToY

+0

@Kamil. Это также потерпит неудачу 31 декабря, когда у кого-то будет свой день рождения 1 января. – SeToY

ответ

7

Вы можете сделать это в одной строке как это:

context.Addresses.Where(adr => adr.DateOfBirth != null).OrderBy(adr => EntityFunctions.DiffDays(DateTime.Today, EntityFunctions.AddYears(adr.DateOfBirth, EntityFunctions.DiffYears(adr.DateOfBirth, DateTime.Today) + ((adr.DateOfBirth.Month < DateTime.Today.Month || (adr.DateOfBirth.Day <= DateTime.Today.Day && adr.DateOfBirth.Month == DateTime.Today.Month)) ? 1 : 0)))).Take(15).ToList(); 

Или в более удобном для чтения формате:

var query = from adr in context.Addresses 
      where adr.DateOfBirth != null 
      let diffYears = EntityFunctions.DiffYears(adr.DateOfBirth, DateTime.Today) 
      let birthdayOccurred = adr.DateOfBirth.Month < DateTime.Today.Month || (adr.DateOfBirth.Day <= DateTime.Today.Day && adr.DateOfBirth.Month == DateTime.Today.Month) 
      let nextBirthdate = EntityFunctions.AddYears(adr.DateOfBirth, diffYears + (birthdayOccurred ? 1 : 0)) 
      let daysToBirthdate = EntityFunctions.DiffDays(DateTime.Today, nextBirthdate) 
      orderby daysToBirthdate 
      select adr; 

var result = query.Take(15).ToList(); 
+0

Это великолепно работает. Спасибо, я очень благодарен! :) – SeToY

+0

@SeToY Можете ли вы попробовать запустить идею из моего ответа в своем наборе данных - я думаю, что это превзойдет этот ответ. – kape123

+0

@ kape123 Я обязательно сделаю, еще не видел. Попробует завтра и вернусь к тебе! – SeToY

1

Попробуйте что-нибудь в этом роде; (Это работает - я проверил)

//A mock up value for comparison (as DayOfYear not supported in Linq) 
int doy = DateTime.Today.Month * 31 + DateTime.Today.Day; 

var results = Addresses.Where(a => a.DateOfBirth != null) 
      .OrderBy(a => 
      (a.DateOfBirth.Value.Month * 31 + a.DateOfBirth.Value.Day) + 
    (a.DateOfBirth.Value.Month * 31 + a.DateOfBirth.Value.Day > doy ? 0 : 400)) 
      .Take(15).ToList(); 
+0

Это неправильно. Когда текущая дата - 8 января - она ​​не вернет строку с 7 февраля (это более поздняя дата), потому что 7 не больше 8 (сегодня). – Kamil

+0

Я думаю, что это все еще неправильно. Он вернет данные, когда какая-либо часть даты будет больше. Допустим, у нас есть 2013-02-27. Что, если день рождения - 2013-01-28? Ваш код вернется в тот день, потому что 28 больше 27. Вы должны комбинировать месяц и день, может быть, так: 'int mmdd = месяц * 100 + день', затем сравните. В качестве альтернативы можно использовать что-то вроде DayOfYear, но только в сочетании с годом. – Kamil

+1

После последнего редактирования ваш код не будет работать, когда «сегодня» будет 31 декабря, а день рождения будет 1 января следующего года. – Kamil

0

Я не знаком с Linq, я постараюсь помочь с некоторым псевдокодом.

Самое важное условие должно выглядеть следующим образом:

Date(CurrentDate.Year, DateOfBirth.Month, DateOfBirth.Day) >= CurrentDate 
|| ' OR 
Date(CurrentDate.Year + 1, DateOfBirth.Month, DateOfBirth.Day) >= CurrentDate 

Это будет работать 31 декабря тоже.

Альтернатива:

// consider this as pseudocode, I didnt tested that in C# 

function GetNextBirthday(DateTime DateOfBirth) 
{ 
int yearOfNextBirthday; 

int birthdayMMDD = DateOfBirth.Month*100 + DateOfBirth.Day; 
int todayMMDD = CurrentDate.Month*100 + CurrentDate.Day; 

    if (birthdayMMDD >= todayMMDD) 
    { 
     yearOfNextBirthday = CurrentDate.Year; // this year 
    } 
    else 
    { 
     yearOfNextBirthday = CurrentDate.Year + 1; // next year 
    } 

DateTime nextBirthday; 

// you have to write this line yourself, i dont remember how to make date from Y, M, D 
nextBirthday = DateFromYMD(yearOfNextBirthday, DateOfBirth.Month, DateOfBirth.Day); 

return nextBirthday; 
} 
1

Я не уверен, что вы можете сделать это как однострочника. Конечно, не с какой-либо степенью ясности.

Необходимые шаги:

  1. Создать упорядоченный список, содержащий только даты рождения, где месяц/день приходит после того, как сегодня.
  2. Создайте упорядоченный список, содержащий только даты рождения, где месяц/день до сегодняшнего дня.
  3. Добавить второй список к первому, теперь у вас есть один список, отсортированный по номеру .
  4. Возьмите первый 15.

Я думаю, что C# код будет выглядеть примерно так (Вы, возможно, потребуется добавить список или два.)

var list1 = Addresses.Where(adr => adr.DateOfBirth != null && (adr.DateOfBirth.Value.Month > DateTime.Today.Month || (adr.DateOfBirth.Value.Month == DateTime.Today.Month && adr.DateOfBirth.Value.Day >= DateTime.Today.Day))).ToList(); 
var list2 = Addresses.Where(adr => adr.DateOfBirth != null && (adr.DateOfBirth.Value.Month < DateTime.Today.Month || (adr.DateOfBirth.Value.Month == DateTime.Today.Month && adr.DateOfBirth.Value.Day < DateTime.Today.Day))).ToList(); 
var fullList = list1.Add(list2); 
+0

Вы не можете создать списки дат рождения до и после сегодняшнего дня. Первая причина: по 31 декабря ваш список более длинных дат будет пустым. Когда у кого-то есть день рождения 1 января - он будет следующим человеком с днями рождения, но вы не увидите этого. – Kamil

+0

Я предполагаю, что его список - это люди, которые уже родились (иначе они еще не могут быть клиентами). Первый список - это люди, чей день рождения сегодня или позже. Второй список - это люди, чьи дни рождения уже прошли. Объединив их таким образом, я создал список дней рождения в следующем году. – ThatBlairGuy

0

Вот мой вход для «один лайнера»:

DateTime now = DateTime.Now; 
var next15 = 
    from a in db.Addresses 
    where a.DateOfBirth != null 
    let diff = EntityFunctions.DiffSeconds(
     EntityFunctions.AddYears(now, -EntityFunctions.DiffYears(a.DateOfBirth, now)), 
     a.DateOfBirth) 
    orderby diff >= 0 ? diff : diff + 366*24*60*60 
    select new a; 

var res = next15.Take(15).ToList(); 

Просто протестировано с базой данных SQL - и он работает как шарм;)

0

Вот такое же решение, как @Aducci но с обнуляемой датой и тому DBFunctions, поскольку EntityFunctions устарели.

  pacientes = from paciente in pacientes 
       where paciente.Nascimento != null 
       let diffYears = DbFunctions.DiffYears(paciente.Nascimento, DateTime.Today) 
       let birthdayOccurred = paciente.Nascimento.Value.Month < DateTime.Today.Month 
       || (paciente.Nascimento.Value.Day <= DateTime.Today.Day && paciente.Nascimento.Value.Month == DateTime.Today.Month) 
       let nextBirthdate = DbFunctions.AddYears(paciente.Nascimento, diffYears + (birthdayOccurred ? 1 : 0)) 
       let daysToBirthdate = DbFunctions.DiffDays(DateTime.Today, nextBirthdate) 
       orderby daysToBirthdate 
       select paciente; 

 Смежные вопросы

  • Нет связанных вопросов^_^