Честно говоря, это не тот сценарий, для которого предназначен Linq to SQL.Linq to SQL по сути является тонкой оболочкой базы данных;Предполагается, что ваша сущностная модель должна близко отражать вашу модель данных, и часто ваша «сущностная модель» Linq to SQL просто не подходит для использования в качестве вашей предметной модели (которая является «моделью» в MVC).
Ваш контроллер должен использовать какой-либо репозиторий или службу.Этот объект должен нести ответственность за загрузку конкретных объектов вместе с любых дополнительных данных, необходимых для модели представления.Если у вас нет репозитория / службы, вы можете встроить эту логику непосредственно в контроллер, но если вы будете делать это много, то в итоге вы получите хрупкий дизайн, который сложно поддерживать - лучше начать схороший дизайн с самого начала.
Не не пытайтесь спроектировать свои классы сущностей для ссылки на DataContext
.Именно в такой ситуации ORM, такие как Linq to SQL, пытаются избежать .Если ваши сущности на самом деле знают о DataContext
, то они нарушают инкапсуляцию, предоставляемую Linq для SQL, и пропускают реализацию для открытых вызывающих абонентов.
Вы должны иметь один ответственный классдля сборки моделей представлений и этот класс должен знать либо сам DataContext
, либо различные другие классы, которые ссылаются на DataContext
.Как правило, рассматриваемый класс, как указано выше, является репозиторием домена какого-либо вида, который абстрагирует весь доступ к базе данных.
PS Некоторые люди будут настаивать на том, что репозиторий должен иметь дело исключительно с доменом.объекты, а не объекты представления (просмотра) и обозначают последние как services или builders ;Назовите это как хотите, принцип по сути тот же, класс, который оборачивает ваши классы доступа к данным и отвечает за загрузку одного определенного типа объекта (модель представления).
Допустим, вы 'создание сайта для автоматической торговли, в котором необходимо отобразить информацию о модели домена (фактический автомобиль / листинг), а также некоторую информацию, связанную, но не связанную, которая должна быть получена отдельно (скажем, диапазон цен для этой конкретной модели)).Таким образом, у вас будет модель вида, подобная этой:
public class CarViewModel
{
public Car Car { get; set; }
public decimal LowestModelPrice { get; set; }
public decimal HighestModelPrice { get; set; }
}
Конструктор модели вашего представления может быть таким простым:
public class CarViewModelService
{
private readonly CarRepository carRepository;
private readonly PriceService priceService;
public CarViewModelService(CarRepository cr, PriceService ps) { ... }
public CarViewModel GetCarData(int carID)
{
var car = carRepository.GetCar(carID);
decimal lowestPrice = priceService.GetLowestPrice(car.ModelNumber);
decimal highestPrice = priceService.GetHighestPrice(car.ModelNumber);
return new CarViewModel { Car = car, LowestPrice = lowestPrice,
HighestPrice = highestPrice };
}
}
Вот и все.CarRepository
- это репозиторий, который упаковывает ваш DataContext
и загружает / сохраняет Cars
, а PriceService
по существу упаковывает кучу хранимых процедур, настроенных в том же DataContext
.
Может показаться, чтомного усилий, чтобы создать все эти классы, но как только вы в этом разберетесь, это действительно не так много времени, и вы в конечном итоге найдете его на способ проще в обслуживании.
Обновление: ответы на новые вопросы
Куда идут файлы репозитория?В папке «Модели» или я могу создать папку «Репозитории» только для них?
Репозитории являются частью вашей модели, если они отвечают за сохранение классов модели.Если они имеют дело с моделями представления (они также являются «службами» или «создателями моделей представления»), то они являются частью вашей логики представления;технически они находятся где-то между контроллером и моделью, поэтому в моих приложениях MVC у меня обычно есть и пространство имен Model
(содержащее классы реального домена), и пространство имен ViewModel
(содержащее классы представления).
Как репозиторий знает о DataContext?
В большинстве случаев вы захотите передать его через конструктор.Это позволяет вам совместно использовать один и тот же экземпляр DataContext
в нескольких репозиториях, что становится важным, если вам необходимо записать модель представления, включающую несколько объектов домена.
Кроме того, если позже вы решите использовать платформу Dependency Injection (DI), она может автоматически обрабатывать все разрешения зависимостей (связывая DataContext
как область действия HTTP-запроса). Обычно ваши контроллеры не должны создавать DataContext
экземпляров, они должны фактически внедряться (опять же через конструктор) в уже существующие отдельные репозитории, но это может немного усложниться без интегрированной среды DI, так что если вы его нет, нормально (не очень), чтобы ваши контроллеры действительно создавали эти объекты.
В моей папке Models есть папка «Коллекции», которая действительно служит ViewModels
Это неправильно. Ваша модель просмотра не является вашей моделью. Модели представлений принадлежат представлению, которое отделено от вашей доменной модели (к которой относится «M» или «модель»). Как уже упоминалось выше, я бы предложил создать пространство имен ViewModel
, чтобы избежать раздувания пространства имен Views
.
Итак, все это где и как будет плагин для хранилища?
См. Несколько параграфов выше - хранилище должно быть введено с DataContext
, а контроллер должен быть введен с хранилищем. Если вы не используете DI-фреймворк, вы можете сойти с рук, когда ваш контроллер создаст DataContext
и репозитории, но постарайтесь не слишком цементировать последний дизайн, вы захотите очистить его позже.
Кроме того, какой смысл в интерфейсе?
Прежде всего, вы можете изменить свою модель персистентности, если это будет необходимо. Возможно, вы решили, что Linq to SQL слишком ориентирован на данные, и вы хотите переключиться на что-то более гибкое, например Entity Framework или NHibernate. Возможно, вам нужно реализовать поддержку Oracle, mysql или какой-либо другой базы данных не от Microsoft. Или, возможно, вы полностью намереваетесь продолжать использовать Linq to SQL, но хотите иметь возможность писать модульные тесты для своих контроллеров; Единственный способ сделать это - вставить фиктивные репозитории в контроллеры, и для этого они должны быть абстрактного типа.
Продолжая, было бы лучше иметь объект абстракции, который собирает всю информацию для реального объекта? Например, объект IJob
, который будет иметь все свойства Job
+ дополнительные свойства, которые я хочу добавить, например Name
?
Это более или менее то, что я рекомендовал в первую очередь, хотя вы сделали это с помощью проекции, которую будет сложнее отлаживать. Лучше просто позвонить SP в отдельной строке кода и объединить результаты потом.
Кроме того, вы не можете использовать тип интерфейса для своего домена или модели представления. Мало того, что это неправильная метафора (модели представляют неизменные законы вашего приложения, они не должны предполагаться для изменения, если не изменяются требования реального мира), но на самом деле это невозможно; интерфейсы не могут быть привязаны к данным, потому что нечего создавать при публикации.
Так что да, у вас вроде есть правильная идея, за исключением того, что (а) вместо IJob
это должно быть ваше JobViewModel
, (b) вместо IJobRepository
это должно быть JobViewModelService
и (c) вместо непосредственного создания экземпляра DataContext
он должен принять его через конструктор.
Имейте в виду, что цель всего этого состоит в том, чтобы сохранить чистый, обслуживаемый дизайн. Если у вас есть 24-часовой срок выполнения, вы все равно можете заставить его работать , просто вставив всю эту логику прямо в контроллер. Только не оставляйте это так долго, иначе ваши контролеры (d) превратятся в мерзости Бого-объекта.