Как избавиться от контекста данных после использования - PullRequest
2 голосов
/ 20 мая 2010

У меня есть класс-член, который возвратил IQueryable из контекста данных

    public static IQueryable<TB_Country> GetCountriesQ()
    {
        IQueryable<TB_Country> country;

        Bn_Master_DataDataContext db = new Bn_Master_DataDataContext();

        country = db.TB_Countries
            .OrderBy(o => o.CountryName);

        return country;
    }

Как видите, я не удаляю контекст данных после использования. Потому что, если я удаляю его, код, вызывающий этот метод, не может использовать IQueryable (возможно, из-за отложенного выполнения?) Как заставить немедленное выполнение к этому методу? Так что я могу распоряжаться контекстом данных ..

Спасибо: D

Ответы [ 2 ]

3 голосов
/ 20 мая 2010

Пример, данный Codeka, верен, и я бы посоветовал написать ваш код с этим, когда метод вызывается уровнем представления. Однако избавиться от DataContext классов немного сложно, поэтому я хотел бы добавить кое-что по этому поводу.

Объекты домена, сгенерированные LINQ to SQL (в вашем случае класс TB_Countries) часто содержат ссылку на класс DataContext. Эта внутренняя ссылка необходима для отложенной загрузки. Когда вы получаете доступ, например, к списку объектов, на которые ссылаются (например, TB_Country.States), LINQ to SQL запросит у вас базу данных. Это также произойдет с лениво загруженными столбцами.

Когда вы утилизируете DataContext, вы предотвращаете его повторное использование. Поэтому, когда вы возвращаете набор объектов, как вы делали в вашем примере, невозможно вызвать свойство States для экземпляра TB_Country, потому что оно выдаст ObjectDisposedException.

Это не значит, что вы не должны распоряжаться DataContext, потому что я считаю, что вы должны. То, как вы должны решить эту проблему, немного зависит от выбранной вами архитектуры, но IMO у вас в основном есть два варианта:

Вариант 1. Поставьте DataContext для метода GetCountriesQ. Обычно вы хотите сделать это, когда ваш метод является внутренним методом на бизнес-уровне и является частью более крупной (бизнес) транзакции. Когда вы предоставляете DataContext извне, он создается за пределами области действия метода и не должен его утилизировать. Вы можете расположить его на более высоком уровне. В этой ситуации ваш метод в основном выглядит следующим образом:

public static IQueryable<TB_Country> GetCountriesQ(
    Bn_Master_DataDataContext db)
{
    return db.TB_Countries.OrderBy(o => o.CountryName);
}

Вариант 2. Не возвращать никакие доменные объекты из метода GetCountriesQ. Это решение полезно, когда метод является общедоступным на вашем бизнес-уровне и будет вызываться на уровне представления. Вы можете обернуть данные в специально созданный объект ( DTO ), который содержит только данные и не содержит скрытых ссылок на DataContext. Таким образом, вы имеете полный контроль над связью с базой данных и можете распоряжаться DataContext, как следует. Я написал больше о нем на SO здесь . В этой ситуации ваш метод в основном выглядит следующим образом:

public static CountryDTO[] GetCountriesQ()
{
    using (var db = new Bn_Master_DataDataContext())
    {
        var countries;
            from country in db.TB_Countries
            orderby country.CountryName
            select new CountryDTO()
            {
                Name = country.CountryName,
                States = (
                    from state in country.States
                    order by state.Name
                    select state.Name).ToList();
            };

        return countries.ToArray();
    }
}

public class CountryDTO
{
    public string Name { get; set; }
    public List<StateDTO> States { get; set; }
}

Как вы прочтете здесь есть некоторые умные вещи, которые вы можете сделать, чтобы сделать использование DTO менее болезненным.

Надеюсь, это поможет.

3 голосов
/ 20 мая 2010

Вы можете преобразовать запрашиваемый в список, например так:

public static List<TB_Country> GetCountriesQ()
{
    using(var db = new Bn_Master_DataDataContext())
    {
        return db.TB_Countries
            .OrderBy(o => o.CountryName).ToList();
    }
}
...