LinqToSql объявляет и создает экземпляр передовой практики DataContext? - PullRequest
15 голосов
/ 14 февраля 2009

Какова наилучшая практика с точки зрения настройки моего DataContext для легкого доступа в моих расширенных классах LinqToSql?

Например, у меня есть объект «Пользователь» в моем dbml, и я хочу добавить методы к этому классу так:

Partial Public Class User

    Public Function GetUser(ByVal UserID as Integer) as User
         'Do Work
    End Function

End Class

Чтобы получить доступ к моему DataContext, я должен объявить его внутри метода следующим образом:

Partial Public Class User

    Public Function GetUser(ByVal UserID as Integer) as User
         Dim dc as New MyDataContext()
         Return (From u in dc.Users Where u.ID = UserID).Single()
    End Function

End Class

Я бы не хотел делать это для каждого метода. Обычно (если бы я не расширял dbml-классы LinqToSql), я мог бы просто сделать это:

Partial Public Class User
    Private dc as MyDataContext

    Public Sub New()
         dc = new MyDataContext()
    End Sub

    Public Function GetUser(ByVal UserID as Integer) as User
         Return (From u in dc.Users Where u.ID = UserID).Single()
    End Function

    Public Function GetAllUsers() as IEnumerable(Of User)
         Return From u in dc.Users
    End Function

    'etc...

End Class

Это позволило бы мне получить доступ к тексту данных для каждого метода без необходимости каждый раз объявлять его заново. Но, конечно, вы не можете этого сделать, потому что в dbml уже есть конструктор. И добавление кода в dbml всегда перезаписывается, если что-то меняется.

У кого-нибудь есть какие-нибудь хорошие идеи о том, как сэкономить здесь лишний код?

ТИА!

Ответы [ 5 ]

14 голосов
/ 14 февраля 2009

Во-первых, убедитесь, что вы утилизируете свой DataContext, когда закончите! Он может быть тяжелым маленьким ублюдком ( edit не тяжелый для создания экземпляра, но тяжелый для хранения, если вы продолжаете использовать его без утилизации); Вы не хотите, чтобы старые DataContexts слонялись в памяти.

Во-вторых, DataContext предназначен для представления одной логической транзакции . Например. вы должны создавать новую каждый раз, когда хотите начать новую транзакцию, и избавляться от нее, когда эта транзакция завершена. Так что для ваших целей это вероятно область применения GetUser метода. Если у вас есть серия вызовов БД, которые необходимо сделать группой, все они должны использовать один и тот же DC, прежде чем избавиться от него.

12 голосов
/ 14 февраля 2009

Как сказал Рекс М , текст данных предназначен для создания, использования и удаления для каждой логической транзакции. Подобные шаблоны иногда называют «единицей работы».

Самый распространенный (как я знаю) способ сделать это - создать экземпляр вашего datacontext в блоке using. Я давно не пользовался VB, но он должен выглядеть примерно так:

Using dc As New MyDataContext()
   user = (From u in dc.Users Where u.ID = UserID).Single()
End Using

Это не только усиливает внешний вид транзакции / единицы работы (через физическую форму кода), но и обеспечивает вызов Dispose () для вашего текста данных, когда блок заканчивается.

См. эту страницу MSDN :

Как правило, экземпляр DataContext рассчитан на одну единицу работа "однако ваше приложение определяет этот термин. DataContext - это легкий и не дорогой Создайте. Типичный LINQ to SQL приложение создает DataContext экземпляры в области видимости метода или как член недолговечных классов, которые представляют собой логический набор связанных операции с базой данных.

0 голосов
/ 14 февраля 2009

Может быть проще, если вы оставите класс User в одиночестве и разрешите среде IDE обрабатывать его создание.

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

Конструктор UserDataProvider может создавать глобальный экземпляр объекта контекста данных для повторного использования. Это выглядело бы примерно так (в C # и непроверенном коде, так что терпите меня):

public class UserDataProvider 
{
    private UserDataContext _data = null;

    public UserDataProvider()
    {
        _data = new UserDataContext();
    }

    public User GetUser(int userID)
    {
        return _data.Users.FirstOrDefault(u => u.UserID == userID);
    }
}

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

public class UserDataProvider 
{
    private UserDataContext _dataContext;

    private UserDataContext DataContext 
    {
        get
        {
            if (_data == null)
                _data = new UserDataContext();

            return _data;
        }
    }

    public User GetUser(int userID)
    {
        return DataContext.Users.FirstOrDefault(u => u.UserID == userID);
    }
}
0 голосов
/ 14 февраля 2009

Есть несколько разных способов сделать это, я думаю, это будет хорошей практикой. Сначала вы можете использовать шаблон Repository, где вы запрашиваете Repository для объекта, он отправляется в базу данных, извлекает объект - возможно, отсоединяя его от контекста данных или сохраняя контекст данных в зависимости от реализации Repository - и возвращает его вам. Методы фабрики для ваших объектов будут находиться в репозитории, а не в самих сущностях. Вы, вероятно, использовали бы рефлексию и обобщения, чтобы минимизировать количество методов, которые вы должны реализовать, и сохранить ваш код СУХИМ.

Другой способ, и способ, которым LINQtoSQL изначально предназначался для использования IMHO, - это создание контекста данных для каждого набора операций с базой данных, которые вы собираетесь выполнять. При этом создание контекста данных происходит и за пределами сущности, обычно в классе, использующем сущности, а не на уровне данных вообще. Вы также можете добавить методы в контекст данных - сделать свой реальный контекст данных абстрактным и наследовать его - снова используя отражение, чтобы выполнить некоторые из общих функций поиска, чтобы вам не приходилось повторять их. Возможно, вам придется использовать шаблон базы данных, такой как ActiveRecords, где столбцы идентификаторов всегда имеют одинаковое имя, чтобы сделать эту работу.

С другой стороны, вы можете использовать nHibernate или Castle ActiveRecord вместо репликации любого из вышеперечисленных в вашем собственном решении.

0 голосов
/ 14 февраля 2009

Я думаю, возможно, настоящая проблема в том, что User, вероятно, не подходящее место для вызова члена экземпляра GetUser.

...