2013-11-09 3 views
1

У меня есть выражение LINQ:Используя специальный метод в LINQ к Entities

 var users = db.Relationships.Where(i => i.RelationshipId== relId) 
      .Select(s => s.User).Distinct().Select(s => new UserViewModel() { 
      Username = s.Username, 
      LastActiveDateTime = s.LastActive, // DateTime, I want it to be a string filtered through my custom GetFriendlyDate method 
     }).ToList(); 

     // convert all DateTimes - yuck! 
     foreach (var userViewModel in users) { 
      userViewModel.LastActive = DateFriendly.GetFriendlyDate(userViewModel.LastActiveDateTime); 
     } 

Это решение работает, но он чувствует себя неправильно

  • должны перебрать все users после получения их от db, просто переформатировать свойство на каждом отдельном
  • имеют свойство DateTime на моей модели ViewModel только для того, чтобы впоследствии его можно было преобразовать в строку и никогда не касаться снова

Есть ли способ использовать метод GetFriendlyDate непосредственно в запросе?

+1

И вы знаете, что смешно? Многие думают, что они могут тестировать EF-код. Они создают поддельный контекст db в IDbSet в памяти и пишут код, как указано выше, и он проходит тест. Но на производстве ... :) –

ответ

2

Возможные решения, стоит упомянуть:

Have A GE олучатель свойства вашей ViewModel, который будет возвращать трансформируется строкой, что-то вроде:

public string LastActive 
{ 
    get 
    { 
     return DateFriendly.GetFriendlyDate(LastActiveDateTime);   
    } 
} 

Хотя это не решает проблему с существующей колонкой LastActiveDateTime, преобразование будет применяться только в момент использования (с вашей точкой зрения, скорее всего, - В любом случае, если вы попытаетесь использовать его где-нибудь в запросе, он не будет работать по той причине, о которой вы уже знаете), поэтому не нужно итерации вручную.

Создать вид, который преобразует данные на стороне сервера; поэтому ваши данные уже будут возвращены в нужном вам формате, если вы используете DBFirst, возможно, это самое простое и быстрое решение;

Наконец, вы можете использовать ToList() дважды, раз перед тем выбора нового ViewModel() (или по телефону AsEnumerable(), или найти другой способ материализовать запрос). Он будет извлекать данные из базы данных и позволит вам выполнять любые функции C#, которые вы хотите непосредственно в запросе после ToList(). Но, как упоминалось ранее, речь идет о получении всех данных, которые соответствуют критериям ToList() - в большинстве случаев это не подходящее решение.

А вот некоторые дополнительные показания:

How can I call local method in Linq to Entities query?

-2

Не работает ли следующая работа?

var users = db.Relationships.Where(i => i.RelationshipId== relId) 
     .Select(s => s.User).Distinct().Select(s => new UserViewModel() { 
     Username = s.Username, 
     LastActiveDateTime = DateFriendly.GetFriendlyDate(s.LastActive)   
    }).ToList(); 
+0

нет, вот в чем проблема – SB2055

0

Я тестировал его в LINQpad, и он работает. Он по-прежнему выполняет итерации над пользователями (с помощью LINQ), но вам не нужно добавлять свойство DateTime в класс viewmodel. Также вы можете преобразовать коллекцию пользователей в коллекцию объектов UserViewModel с помощью Automapper. Конечно, он все равно будет перебирать пользователей, но вы этого не увидите.

Придется создать код установки, конечно, потому что у меня нет вашей базы данных.

void Main() 
{ 
     var db = new List<User> { 
      new User { LastActive = DateTime.Now, Username = "Adam", Lastname = "Nowak" }, 
      new User { LastActive = DateTime.Now.AddYears(1), Username = "Eve", Lastname = "Kowalska"} 
     }; 

     // select only properties that you need from database 
     var users = db 
      .Select(user => new { Username = user.Username, LastActive = user.LastActive}) 
      .Distinct() 
      .ToList(); 

     var usersVM = from u in users 
     select new UserViewModel { Username = u.Username, LastActiveDateTime = DateFriendly.GetFriendlyDate(u.LastActive)}; 

     usersVM.Dump(); 
} 

     class User 
     { 
      public DateTime LastActive; 
      public string Username; 
      public string Lastname; 
     }; 
     class UserViewModel 
     { 
      public string Username; 
      public string LastActiveDateTime; 
     } 

     static class DateFriendly 
     { 
      public static string GetFriendlyDate(DateTime date)   
      { 
       return "friendly date " + date.Year; 
      } 
     } 

И это выводит

Пользователь LastActiveDateTime

Адам дружеский 2013 Дата

Eve дружеский дата 2014

+0

Работает, так как вы имеете дело с локальным списком объектов. Вопрос: как выполнить этот запрос на EntityCollection. И с этой ситуацией у вас будут проблемы ... – Dmytro

+0

Вы правы. Я починил это. Благодарю. –

+0

Но это возвращает вас к квадрату. –

-1

Там нет прямого метода Concert.ToDate для LINQ. Но вы можете попробовать использовать метод DateAdd из класса SqlFunctions:

var users = db.Relationships.Where(i => i.RelationshipId== relId) 
    .Select(s => new 
    { 
     s.User.Username, 
     LastActive=SqlFunctions.DateAdd("d",0, s.LastActive) 
    }) 
    .ToList().Select(s => new UserViewModel() 
    { 
     Username = s.Username, 
     LastActiveDateTime = s.LastActive 
    }); 
Смежные вопросы