Какова наилучшая стратегия LINQ-to-SQL для избавления от DataContext внутри методов?

Я понимаю, что рекомендуется использовать блок using при получении данных из классов LINQ-to-SQL, как показано ниже.

Однако, когда я это делаю, я могу получить доступ только к поверхностным свойствам orders (например, Order.OrderId), но не к более глубоким свойствам (например, Customer.CustomerName), поскольку на этом этапе они, похоже, утилизируются.

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

Что здесь лучше всего?

using System;
using System.Collections.Generic;
using System.Linq;
using TestExtn2343.Models;

namespace TestExtn2343
{
    class Program
    {
        public static void Main(string[] args)
        {

            var orders = GetOrders(10, 10);

            orders.ForEach(x =>
            {
                Customer customer = x.Customer;
                if (customer != null)
                {
                    //SUCCEEDS:
                    Console.WriteLine("{0}, {1}", x.OrderID);

                    //FAILS: "
                    Console.WriteLine("{0}, {1}", x.OrderID, x.Customer.ContactName.ToString());
                }
            });

            Console.ReadLine();
        }

        public static List<Order> GetOrders(int skip, int take)
        {
            using (MainDataContext db = new MainDataContext())
            {
                List<Order> orders = (from order in db.Orders
                                      select order).Skip(skip).Take(take).ToList();
                return orders;
            }
        }

    }
}

Отвечать:

Спасибо, Адам, используя ваше предложение, я заставил свой код работать следующим образом:

public static void Main(string[] args)
{
    using (MainDataContext db = new MainDataContext())
    {
        GetOrders(db, 10, 10).ForEach(x => Console.WriteLine("{0}, {1}", x.OrderID, x.Customer.ContactName.ToString()));
    }
    Console.ReadLine();
}

public static List<Order> GetOrders(MainDataContext db, int skip, int take)
{
    List<Order> orders = (from order in db.Orders
                          select order).Skip(skip).Take(take).ToList();
    return orders;
}

person Edward Tanguay    schedule 05.11.2009    source источник


Ответы (2)


Невозможно получить доступ к более глубоким свойствам объекта, потому что LINQ-to-SQL использует отложенную загрузку (то есть он автоматически извлекает эти записи по мере необходимости, поэтому при первом доступе к ним он выполняет операция с базой данных). Поскольку DataContext удален, он не может выполнять необходимые операции с базой данных. Можно иметь такие свойства, которые загружаются «с нетерпением» (то есть во время первоначального извлечения), но вам нужно знать все это заранее.

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

Вот хорошая запись в блоге об DataContext управлении сроком службы.

person Adam Robinson    schedule 05.11.2009

Если вы точно знаете, что хотите получить клиентов, вы можете указать это в DataLoadOptions, и он подключит запрос, чтобы загружать их с нетерпением, а не лениво загружать.

Вот статья msdn о DataLoadOptions.

Пример:

var dlo = new DataLoadOptions();
dlo.LoadWith<Order>(o => o.Customer); 
context.DataLoadOptions = dlo;
person Joseph    schedule 05.11.2009