C #, Linq2SQL - трюки, чтобы получить объект ViewModel с данными отношения? - PullRequest
2 голосов
/ 11 марта 2011

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

var query = from ord in ctx.Table_Orders
        select new OrderViewModel()
        {
            OrderId = ord.OrderId,
            OrderSum = ord.OrderSum,
            OrderCurrencyId = ord.OrderCurrencyId,
            OrderCurrencyView = ord.Currency.CurrencyText
        };

Итак, я хочу, чтобы моя ViewModel включала как CurrencyId из объекта домена, так и CurrencyText из связанной таблицы, чтобы он хорошо отображался в представлении.

Этот код прекрасно работает. Он генерирует один вызов БД с объединением для получения CurrencyText. Но модель упрощенная , реальная имеет гораздо больше полей. Я хочу сделать код для повторного использования , потому что у меня много разных запросов, которые возвращают одну и ту же ViewModel. Теперь каждое незначительное изменение в OrderViewModel требует большой поддержки.

Поэтому я переместил код в сам OrderViewModel в качестве конструктора.

public OrderViewModel(Table_Order ord)
{
    OrderId = ord.OrderId,
    OrderSum = ord.OrderSum,
    OrderCurrencyId = ord.OrderCurrencyId,
    OrderCurrencyView = ord.Currency.CurrencyText
}

И назовите это так.

var query = from ord in ctx.Table_Orders
        select new OrderViewModel(ord);

Проблема : Соединение пропало Запрос БД больше не оптимизирован. Теперь я получаю 1 + N вызовов в базу данных для получения CurrencyText для каждой строки.

Любые комментарии приветствуются. Может быть, я пропустил другой отличный подход.

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

var query = ctx.Table_Orders.Select(m =>
       newOrderViewModel(m, m.Currency.CurrencyText));

Вызов DB снова оптимизирован. Но это все еще не чувствует, что я там еще! Какие уловки Вы знаете для этого случая?


РЕДАКТИРОВАТЬ: окончательное решение Благодаря подсказке @Muhammad Adeel Zahid я пришел к этому решению. Я создал расширение для IQueryable

public static class Mappers
{
    public static IEnumerable<OrderViewModel> OrderViewModels(this IQueryable<Table_Order> q)
    {
        return from ord in q
                select new OrderViewModel()
                {
                    OrderId = ord.OrderId,
                    OrderSum = ord.OrderSum,
                    OrderCurrencyId = ord.OrderCurrencyId,
                    OrderCurrencyView = ord.Currency.CurrencyText
                };
    }
}

Теперь я могу сделать это, чтобы получить весь список

var orders = ctx.Table_Order.OrderViewModels().ToList();

или это, чтобы получить один элемент, или что-то среднее между Где (x => ..)

var order = ctx.Table_Order
   .Where(x => x.OrderId == id).OrderViewModels().SingleOrDefault();

И это полностью решает этот вопрос. Сгенерированный SQL идеален, а код для перевода объектов можно использовать повторно. Такой подход должен работать как с LINQ to SQL, так и с LINQ to Entities. (Не проверено с последним) Еще раз спасибо @Muhammad Adeel Zahid

Ответы [ 2 ]

1 голос
/ 25 марта 2011

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

public IEnumerable<OrderViewModel> GetAllOrders()
{
    return from ord in ctx.Table_Orders
        select new OrderViewModel()
        {
            OrderId = ord.OrderId,
            OrderSum = ord.OrderSum,
            OrderCurrencyId = ord.OrderCurrencyId,
            OrderCurrencyView = ord.Currency.CurrencyText
        };

} 

Теперь вы можете отфильтровать эти записи и вернуть другое перечисление, например, для currencyID

public IEnumerable<OrderViewModel> GetOrdersByCurrency(int CurrencyID)
{
      return GetAllOrders().Where(x=>x.CurrencyId == CurrencyID);
}

СейчасВы также можете захотеть найти одну запись из всех этих моделей представлений

public OrderViewModel GetOrder(int OrderID)
{
      return GetAllOrders().SingleOrDefault(x=>x.OrderId == OrderID);
}

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

1 голос
/ 11 марта 2011

Вы можете избежать проблемы с N + 1 запросами, если Linq2SQL с готовностью загрузит ссылочные объекты, необходимые для построения ваших моделей представления.Таким образом, вы можете создать один список объектов (и некоторые ссылочные объекты) и использовать его для создания всего.Взгляните на это сообщение в блоге .

Одно предупреждение: этот метод (установка LoadOptions для контекста данных Linq2SQL) может быть выполнен только один раз для контекста данных.Если вам нужно выполнить второй запрос с другой конфигурацией загрузки, вы должны заново инициализировать контекст данных.Я автоматизировал это с помощью простого класса-оболочки для моего контекста.

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