Как сначала создать вычисляемое значение (во время выполнения) в коде Entity Framework - PullRequest
3 голосов
/ 28 мая 2011

У меня есть пользовательский класс в EF Code First, который содержит множество свойств, и у каждого пользователя есть коллекция «Контакты», которые являются другими пользователями в качестве подмножества общего количества пользователей. Другая коллекция "ContactOfOthers" - это просто обратный пример, показывающий, кто имеет этого пользователя в качестве контакта, поскольку это отношение многих ко многим.

public class User {

        [Key]
        public string UserName { get; set; }

        // Lots of other properties not relevant to this question...

        [NotMapped]
        public bool IsMyContact { get; set; }

        public virtual ICollection<User> Contacts { get; set; }
        public virtual ICollection<User> ContactOfOthers { get; set; }

}

Я ввел несопоставленное (не сопоставленное с БД) свойство под названием IsMyContact . Это для случаев, когда пользователь запрашивает группу пользователей, и мне нужно показать в представлении, какие пользователи уже есть в их списке контактов. Так что это свойство должно быть истинным, если пользователь является частью их коллекции «Контакты». Его не следует сохранять в БД, поскольку он может отличаться для одного и того же пользователя в зависимости от пользователя, выполняющего запрос.

Есть ли хороший способ сделать это в запросе из контекста? Конечно, это можно сделать грубо, выполнив два запроса, затем итерируя по основному, ища совпадения в коллекции контактов пользователя, но мне интересно, есть ли более элегантный способ сделать это из одного запроса, проецируя запуск? время вычисляется столбец на это свойство?

Ответы [ 2 ]

3 голосов
/ 28 мая 2011

Я не знаю, как заполнить свойство IsMyContact в User непосредственно в запросе. Но альтернативный подход мог бы заключаться во введении ViewModel, который упаковывает User и имеет дополнительно флаг IsMyContact:

public class UserViewModel
{
    public bool IsMyContact { get; set; }
    public User User { get; set; }
}

(класс User не будет иметь флаг IsMyContact больше.)

Затем вы можете проецировать на этот тип при выполнении запроса:

string me = "That's me"; // name of the user who is selecting

List<UserViewModel> list = context.Users
   .Where(u => ...some filter...)
   .Select(u => new UserViewModel
          {
              IsMyContact = u.ContactOfOthers.Any(c => c.UserName == me),
              User = u
          })
   .ToList();

Преимущества будут следующие: вам нужен только один круговой рейс, и вы не обязаны загружать всю коллекцию Contacts, чтобы определить IsMyContactFlag (но вы можете, если хотите).

Недостаток: вам нужен этот дополнительный тип ViewModel.

2 голосов
/ 28 мая 2011

Это можно сделать, но это будет далеко не «хороший путь», потому что вы не можете вернуть экземпляры вашего типа User. Вы должны написать собственный запрос linq-to-entity и решить две проблемы:

  • Вы не можете проецировать на сопоставленные типы в linq-to-entity
  • Вы не можете получить доступ к не отображенным свойствам в linq-to-entity

Итак, моя непроверенная идея высокого уровня о том, как это сделать:

var query = from u in ctx.Users
            where u.Id != id // don't include current user - you can add other condition
            join c in ctx.Users
                         .Where(x => x.Id == id) // current user
                         .SelectMany(x => x.Contacts)
                on u.Id equals c.Id into leftJoin
            from y in leftJoin.DefaultIfEmpty()
            select new 
                {
                    UserName = u.UserName,
                    IsMyContact = y != null
                };

Это должен быть запрос, который будет загружать пары UserName и информацию, если пользователь контактирует или нет. Если вам нужен экземпляр User, вы должны сделать что-то вроде этого:

var users = query.AsEnumerable()
                 .Select(new User
                      {
                          // Project to list in linq-to-objects
                      });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...