Можете ли вы применить ООП к проекциям Linq? - PullRequest
0 голосов
/ 01 октября 2010

Использование

  • Visual Studio 2010
  • .Net Framework 4
  • C #
  • Linq to Entities

Issue

Я хотел бы иметь возможность применять объектно-ориентированные принципы, такие как DRY и SOLID, к некоторым проекциям Linq.С помощью скомпилированных запросов или переданных параметров я могу до сих пор успешно применять их к остальной части Linq, но не в проекциях.

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

Подробности

На высоком уровне я быхотелось бы иметь возможность динамически управлять типом, используемым в проекции Linq, с помощью стандартного запроса Linq или CompiledQuery.Я использую Linq to Entities в своих примерах и в реальном коде, однако проблема должна быть применима к ядру Linq.

Ниже приведены упрощенные примеры, которые не являются динамическими и не решают проблему.Они исправлены, чтобы всегда использовать FooUser для каждого типа.Я хотел бы иметь возможность динамически контролировать тип пользователя, создаваемого в проекции, и все это будет основано на общем интерфейсе IUser.Это будет или может быть похоже на то, как я могу контролировать, какой тип фильтра запросов.

Альтернативные решения

Я пытаюсь соответствовать DRY, SOLID, а также стараюсь избегать использования enum для обработки, которая является типичным запахом кода.Однако во всех моих попытках и исследованиях мне, кажется, приходилось прибегать к одному из следующих решений:

  1. Реализовать запрос для каждого типа, которые все одинаковы, кроме типа, по которому они фильтруютсяи тип, используемый в проекции.Хотя это нарушает DRY и OCP, я могу инкапсулировать это в одном классе и хранить их близко друг к другу как выполненные запросы.Это потребует, чтобы класс изменился, если я добавлю новый тип или если вы запросите изменения данных.

  2. Реализуйте перечисление с типами и используйте более обобщенный класс Userэто имеет свой тип как свойство.Однако из-за этого мне придется использовать enum в нескольких местах и ​​вводить длинные операторы case для их обработки, чего я бы хотел избежать.

Я бы не хотел выбиратьмежду различными пороками, и имеют реализацию, которая может соответствовать всем принципам SOLID и DRY.Однако, если мне нужно, я думаю, что в итоге получу первую или ее версию.

Примеры

Стандартный простой запрос Linq

using (MyEntities context = new MyEntities())
{
    var results = from u in context.Users
                  where u.UserType == type
                  select new FooUser
                  {
                      Id = u.UserID,
                      Name = u.UserName,
                      Location = u.UserLocation
                  };
}

Скомпилированная версия вышеприведенногоЗапрос

private static readonly Func<MyEntities, int, IQueryable<FooUser>> query = CompiledQuery.Compile<MyEntities, int, IQueryable<FooUser>>(
    (context, type) => from u in context.Users
                       where u.UserType == type
                       select new FooUser
                       {
                           Id = u.UserID,
                           Name = u.UserName,
                           Location = u.UserLocation
                       });-

1 Ответ

0 голосов
/ 01 октября 2010

Я нашел способ сделать это стандартным вызовом метода. Я не выяснил, как это сделать с помощью скомпилированного запроса, это маловероятно.

Мне не было известно об Ограничении Конструктора I в выражении where для универсального выражения. Это может удовлетворить мои потребности. Я хотел бы сделать это с помощью скомпилированного запроса, но могу жить счастливо с этим решением.

public IQueryable<IUser> FooMethod<T>(int type) where T : IUser, new()
{
    using (MyEntities context = new MyEntities())
    {
        var results = from u in context.users
                      where u.usertype == type
                      select new T
                      {
                          id = u.UserId,
                          name = u.UserName,
                          location = u.Userlocation
                      };
        return results; 
    }
}

Я решил опубликовать ответ вместо удаления вопроса по двум причинам, одна из которых в случае, если другие ищут что-то похожее, может оказаться полезной. Тогда, конечно, я мог бы быть далеко от базы, и всегда весело, когда люди пробивают дыры в предметах и ​​смотрят, какие вещи получше.

...