2

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

`context.Entry(ticket).Collection(i => i.TicketItems).Load(); 
      ticket.TicketItems.Clear();` 

Это то, что мой контроллер делал перед тем, чтобы исключить любые ссылки между Ticket и TicketItem. Между Ticket и TicketItem существует отношение «многие ко многим». Таким образом, эти две строки кода, что я использовал до того, чтобы удалить все TicketItems из Ticket

ответ

5

Вы можете иметь два метода в интерфейсе хранилища - один для навигационных ссылок и один для навигации коллекции:

public interface IRepository<T> 
{ 
    void LoadNavigationReference<TReference>(T entity, 
     Expression<Func<T, TReference>> navigationProperty, 
     params Expression<Func<TReference, object>>[] includes) 
     where TReference : class; 

    void LoadNavigationCollection<TElement>(T entity, 
     Expression<Func<T, ICollection<TElement>>> navigationProperty, 
     params Expression<Func<TElement, object>>[] includes) 
     where TElement : class; 
} 

Предполагается, что они должны поддерживать другие вложенные навигационные свойства. Реализация будет:

public class Repository<T> : IRepository<T> 
    where T : class 
{ 
    private readonly MyContext _dbContext; 

    public Repository(MyContext dbContext) 
    { 
     _dbContext = dbContext; 
    } 

    public void LoadNavigationReference<TReference>(T entity, 
     Expression<Func<T, TReference>> navigationProperty, 
     params Expression<Func<TReference, object>>[] includes) 
     where TReference : class 
    { 
     if (includes == null || includes.Length == 0) 
      _dbContext.Entry(entity).Reference(navigationProperty).Load(); 
     else 
      _dbContext.Entry(entity).Reference(navigationProperty).Query() 
       .IncludeMultiple(includes).Load(); 
    } 

    public void LoadNavigationCollection<TElement>(T entity, 
     Expression<Func<T, ICollection<TElement>>> navigationProperty, 
     params Expression<Func<TElement, object>>[] includes) 
     where TElement : class 
    { 
     if (includes == null || includes.Length == 0) 
      _dbContext.Entry(entity).Collection(navigationProperty).Load(); 
     else 
      _dbContext.Entry(entity).Collection(navigationProperty).Query() 
       .IncludeMultiple(includes).Load(); 
    } 
} 

метод IncludeMultiple расширения, используемый выше берется из Ladislav Mrnka's answer here.

Пример ваш вопрос будет выглядеть следующим образом:

repository.LoadNavigationCollection(ticket, i => i.TicketItems); 
ticket.TicketItems.Clear(); 

где repository имеет тип IRepository<Ticket>.

Если TicketItem было другое свойство навигации, скажет TicketItemDetails, вы могли бы охотно загрузить его вместе с TicketItems таким образом:

repository.LoadNavigationCollection(ticket, i => i.TicketItems, 
    t => t.TicketItemDetails); 

Редактировать

BTW как критическое примечание стороны о родовых Хранилище: выше является частью общего репозитория, который имеет на самом деле 16 методов и что я использовал на ранней стадии проекта, прежде чем я остановился, чтобы его расширить и полностью отказался от этого стиля.

В начале хранилища было около 5 методов (как и большинство обычных репозиториев, которые вы видите в Интернете). Было невозможно работать только с этими 5 способами, не теряя при этом много возможностей Entity Framework. Поэтому мне нужно было продлить его шаг за шагом, руководствуясь реальными потребностями в проекте, и он никогда не становился «полным», прежде чем я удалил его из проекта.

Проблема заключается в следующем: если вы продемонстрируете интерфейс кому-либо («здесь у меня есть супер общий и независимый от технологии интерфейс доступа к данным»), он сразу сказал бы «ага, вы используете Entity Framework!». Причина в том, что почти каждый метод является всего лишь оберткой вокруг метода Entity Framework, и вы не можете скрыть это, используя другие имена для методов интерфейса. Весь интерфейс пахнет EF DbContext/Code-First.

Теперь попробуйте реализовать этот интерфейс с другой технологией, чем Entity Framework. Скорее всего, вы столкнетесь с той же проблемой, что и я: Множество методов отсутствует, чтобы использовать возможности этой другой технологии или существующие методы имеют неправильные параметры или существует слишком много методов, которые вы не можете разумно реализовать с помощью другого технологии.

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

На мой взгляд, такой общий репозиторий является типичным примером Leaky Abstraction, где реальная реализация, которую вы имеете в виду, светит через весь интерфейс.

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

+0

Благодарим вас за ответ и ваш ввод. Я новичок в этом общем родовом хранилище и шаблоне работы, но из вашего опыта было бы лучше использовать структуру сущности напрямую? Но как я могу покончить с моими контроллерами? вы думаете, что было бы хорошо придерживаться универсального репозитория, так что мне не нужно создавать много методов? – SOfanatic

+0

Мне нравится ваш комментарий о шаблоне репозитория и ef. Просто не делай этого. Репозиторий - с 2004 года или с тех пор, когда ормы настолько популярны. Также исходный репозиторий обнаружил, добавлял, удалял, сохранял методы. –

+2

@ Luis: Я не рекомендую использовать EF и 'context' непосредственно в контроллере. Разделение проблем является хорошей практикой, но не требует всегда абстракций. То, что я делаю сегодня, - это больше бизнес-логики. В вашем примере у меня, вероятно, был какой-то «класс TicketService» или интерфейс с методом «ClearTicket», и я бы назвал «ticketService.ClearTicket (ticket)». Но в этом методе я использую EF напрямую без репо. Он выводит всю бизнес-логику из контроллера, а не только на доступ к данным. Весь предмет частично зависит от вкуса, вы должны найти свою собственную лучшую практику :) – Slauma

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