Как выставить DataContext из-внутри класса DataContext? - PullRequest
2 голосов
/ 10 ноября 2010

Можно ли выставить DataContext при расширении класса в DataContext? Учтите это:

public partial class SomeClass {
    public object SomeExtraProperty {
        this.DataContext.ExecuteQuery<T>("{SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE}");
    }
}

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

ОБНОВЛЕНИЕ @ Aaronaught

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

Скажем, у меня очень простое приложение, структурированное как (в папках):

  • Контроллеры
  • Модель
  • Просмотры

Куда идут файлы репозитория? В папке Models или я могу создать папку "Repositories" только для них?

В прошлом как хранилище знает о DataContext? Должен ли я создавать новый экземпляр этого в каждом методе репозитория (если это так, что кажется неэффективным ... и не вызовет ли это проблемы с извлечением объекта из одного экземпляра и использованием его в контроллере, который использует другой экземпляр ...)?

Например, у меня сейчас есть такая настройка:

public class BaseController : Controller {
    protected DataContext dc = new DataContext();
}

public class XController : BaseController {
    // stuff
}

Таким образом, у меня есть «глобальный» DataContext, доступный для всех контроллеров, которые наследуются от BaseController. Насколько я понимаю, это эффективно (я могу ошибаться ...).

В моей папке Models у меня есть папка «Коллекции», которая действительно служит ViewModels:

public class BaseCollection {
    // Common properties for the Master page
}

public class XCollection : BaseCollection {
    // X View specific properties
}

Итак, взяв все это, где и как будет плагин для хранилища? Было бы что-то вроде этого (используя реальные объекты моего приложения):

public interface IJobRepository {
    public Job GetById(int JobId);
}

public class JobRepository : IJobRepository {
    public Job GetById(int JobId) {
        using (DataContext dc = new DataContext()) {
            return dc.Jobs.Single(j => (j.JobId == JobId));
        };
    }
}

Кроме того, какой смысл в интерфейсе? Неужели другие сервисы могут подключаться к моему приложению? Что если я не планирую иметь такие возможности?

Продолжая, было бы лучше иметь объект абстракции, который собирает всю информацию для реального объекта? Например, объект IJob, который будет иметь все свойства Job + дополнительные свойства, которые я могу добавить, например Name? Так что хранилище изменится на:

public interface IJobRepository {
    public IJob GetById(int JobId);
}

public class JobRepository : IJobRepository {
    public IJob GetById(int JobId) {
        using (DataContext dc = new DataContext()) {
            return dc.Jobs.Single(j => new IJob {
                Name = dc.SP(JobId)  // of course, the project here is wrong,
                                     // but you get the point...
            });
        };
    }
}

Моя голова сейчас так смущена. Мне бы очень хотелось увидеть учебник от начала до конца, то есть «Файл -> Создать -> Сделать это -> Сделать это».

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

Ответы [ 2 ]

5 голосов
/ 10 ноября 2010

Честно говоря, это не тот сценарий, для которого предназначен 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) превратятся в мерзости Бого-объекта.

1 голос
/ 10 ноября 2010

Замените {SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE} хранимой процедурой, затем Linq to SQL импортирует эту функцию.

Затем можно вызвать функцию непосредственно из контекста данных, получить результаты и передать ее в модель представления.

Я бы не стал создавать свойство, вызывающее контекст данных.Вы должны просто получать значение из уровня сервиса или хранилища всякий раз, когда вам это нужно, вместо того, чтобы встраивать его в один из объектов, созданных Linq для SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...