2009-06-26 5 views
3

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

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

public IList<Bookingcode> FindBookingcode(int id) { 
    return (from b in _db.BOOKINGCODE 
      where b.ID == id 
      select new Bookingcode { 
       Id = b.ID, 
       Name = b.NAME.Trim() 
      }).ToList(); 
} 

Это работает хорошо до сих пор. Но у меня есть много объектов, которые должны быть индивидуально составлены. FindBookingcode() должен возвращать почти полный объект с другими объектами, такими как каталоги и т. Д. Моя проблема в настоящее время является то, что я должен переписать отображение много раз, как в этом примере:

public IList<Bookingcode> FindBookingcode(int id) { 
    return (from b in _db.BOOKINGCODE 
      join c1 in _db.CATALOG on b.CATALOGID equals c1.ID 
      where b.ID == id 
      let refs = (
       from bc1 in _db.BOOKINGCODE 
       join p in _db.PACKAGE on bc1.ID equals p.BOOKINGCODE 
       join bc2 in _db.BOOKINGCODE on p.PACKAGEREF equals bc2.ID 
       join c in _db.CATALOG on bc.CATALOGID on bc2.CATALOGID equals c.ID 
       where bc1.ID == b.ID 
       select new PackageInfo { 
        ID = p.ID 
        BookingcodeRef = new Bookingcode { 
         ID = bc2.ID, 
         Catalog = new Catalog { ID = c.ID } 
        } 
       }) 
      select new Bookingcode { 
       ID = b.ID, 
       PackageInfo = refs.ToList() 
      }).ToList(); 

} 

У меня также есть некоторые обработки L2O в хранилище, которое собирает возвращенные предметы. Еще одна вещь, к которой у меня нет крутого решения, - это способ сообщить репозиторию, что он должен извлечь, например FindBookingcode (id, includePackageInfo, includeCatalog).

Так вот вопросы:

1) Является ли этот подход совершенно глупо?

2) Можете ли вы направить меня к решению, которое упрощает переназначение?

3) Как реализовать механизм критериев для DDD

ответ

1

Вы используете Linq для SQL или Entity Framework?

Я предположил, что вы используете Entity Framework, когда ссылаетесь на «LINQ Entity» в своем вопросе.

Вы должны быть в состоянии сделать это своего рода отображение с помощью Entity Framework навигацию свойства. Вам нужно будет добавить свойства навигации для каждого объекта, который вы хотите сопоставить таким образом. Это так же просто, как рассказать визуальному дизайнеру, который сопоставляет атрибуты с соответствующим атрибутом в другом объекте.

Посмотрите на How do I Entity Framework video series для очень быстрого руководства для начинающих. Я бы рекомендовал посмотреть всю серию, поскольку они очень информативны.

+0

У меня теперь есть простой тестовый проект с Entity Framework и реорганизованными som bits. Свойства навигации работают нормально, и поскольку теперь я могу правильно сопоставить отношения 1: n и n: m, я могу сделать IQueryable avilable. Спасибо, что указал мне в этом направлении. Я просто борюсь с EF Designer V1 и добавил некоторые ручные отношения к представлениям, чтобы обработать эту плохую схему базы данных. –

3

В моих репозиториях у меня есть отдельный метод сборки, который принимает объект LINQ to SQL и возвращает бизнес-объект.

Метод сборки выглядит как (this.Container является контейнером Unity IoC и не важно для примера):

private IGroup BuildGroup(Entities.Group group) 
{ 
    IGroup result = this.Container.Resolve<IGroup>(); 
    result.ID = group.GroupID; 
    result.Name = group.Name; 

    return result; 
} 

Затем каждый метод использует метод сборки для возврата бизнес-объект:

public override IGroup GetByID(int id) 
{ 
    try 
    { 
     return (from g in this.Context.Groups 
       where g.GroupID == id && g.ActiveFlag 
       select this.BuildGroup(g)).Single(); 
    } 
    catch (InvalidOperationException) 
    { 
     return null; 
    } 
} 

Это работает, возвращая каждый объект LINQ to SQL из базы данных и запуская его через метод сборки, поэтому ваш результат в этом случае будет перечислимым для ваших бизнес-объектов вместо объектов LINQ to SQL.

1

Если я вызываю метод репозитория, например

var list = x.FindBookingcode(int id)
Я бы ожидал, что вы сможете добавлять элементы в список и не беспокоиться о том, как он будет сохраняться в базе данных. В реализации примера нет способа, чтобы ваша функция репозитория обнаружила, что кто-то добавил что-то в список, чтобы он ничего не мог с этим поделать.

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

+0

Как я уже сказал в своем ответе на мой вопрос ^^, это действительно то, что нужно рассмотреть. Поэтому при тестировании реализации EF я удалил репозиторий, потому что в основном это просто модель EF с некоторыми расширениями. Итак, теперь можно написать: var customers = ctx.Customers.WithEmail(). WithBookings(). WithRole (CustomerRole.Private) ... и так далее, где WithBookings является короткой средой для фильтров в наборе объектов Transactions. –

0

Прежде всего - долго я буду отвечать за мой ответ ^^ Я был так занят, что забыл ответить.

John, ваше решение довольно приятно решить мою проблему с множественным переназначением.

DoctaJonez, я использую Linq2SQL. Я провел несколько тестов с Entity Framework, но также с NHibernate. Корень проблем отображения состоит в том, что у меня есть заданная схема базы данных, которая иногда очень уродлива. Поэтому при обработке данных у меня много обработки. NHibernate работает достаточно хорошо, и я думаю, что добавлю его в проект в ближайшем будущем.

Ганс, ваша точка зрения совершенно правильная. Но поскольку проект - это просто запрос api для базы данных, в базу данных нет записи. Это скорее dll с услугами, которые используются другими приложениями для получения информации из программного обеспечения для бронирования, которое используется в моей компании.

Вы упомянули «Технические характеристики», что также является хорошим моментом. Поскольку у меня есть огромные поисковые запросы с большим количеством фильтров, мне действительно нужен хороший api для репозитория. Проблема в том, что, например, различные комбинации фильтров также запускают различную логику обработки. Это также должно создать эффективный SQL-код.

Поскольку у меня есть сопоставленные объекты и использование Linq to SQL, я не могу заставить спецификации работать так, как они должны. Таким образом, у меня есть много методов в хранилище для извлечения объектов ти различных crierias, например, так:

Bookingcode FindBookingcode(int id); 
Bookingcode FindBookingcode(string code, string catalog); 
List<Bookingcode> FindBookingcode(); 
List<Bookingcode> FindBookingcode(int[] ids); 
List<Bookingcode> FindBookingcode(string code); 
List<Bookingcode> FindBookingcode(string[] codes); 
List<Bookingcode> FindBookingcodes(Catalog catalog); 

Потому что им не с помощью IQueryable я не могу цепные вещи, как

repo.GetBookingcodes().WithCatalog("WI09").WithCode("XYZ10001"); 

Для больших интерфейсов, таких как Поисковый я использовать объекты фильтра, как так

srv.SearchTransactions(new TransactionSearchFilter { 
    Customer = 1234, Destination = "DXB", ExtractServices = true }); 

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

repo.QueryTransactions() 
    .Include<Customer>() 
    .Include<TransactionsService>() 
    .FilterBy(TransactionSearchFilter.Customer, 1234) 
    .FilterBy(TransactionSearchFilter.Destination, "DXB") 
    .Execute(); 

, который внутренне строит критерии/спецификации. Но это действительно выглядит как Entity Framework, и, возможно, если я глубже, я могу использовать его или NHibernate.

Наиболее проблемные разделы в моем репозитории - это поиск, потому что необходимо создать какой-то динамический SQL с точки зрения производительности. Я играл с PredicateBuilder, но не мог решить некоторые запросы, когда я изменяю/включаю таблицу, если установлены определенные фильтры.

Я думаю, что мне нужно «сканировать» дополнительную документацию. Спасибо за ваши ответы.

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