Рекомендации по использованию веб-приложений LINQ to SQL - PullRequest
14 голосов
/ 07 мая 2010

В своем опыте создания веб-приложений я всегда использовал n-уровневый подход. DAL, который получает данные из базы данных и заполняет объекты, и BLL, который получает объекты из DAL и выполняет любую бизнес-логику, необходимую для них, и веб-сайт, который получает данные для отображения из BLL. Я недавно начал изучать LINQ, и в большинстве примеров показаны запросы, возникающие непосредственно из-за кодов в веб-приложении (возможно, я видел только слишком упрощенные примеры). В n-уровневых архитектурах это всегда рассматривалось как большое нет-нет.
Я немного не уверен в том, как создать новое веб-приложение. Я использовал Обозреватель серверов и конструктор dbml в VS2008 для создания отношений dbml и объектов. Мне кажется немного неясным, будет ли dbml рассматриваться как слой DAL, должен ли веб-сайт вызывать методы внутри BLL, которые затем будут выполнять запросы LINQ и т. Д.
Каковы некоторые общие рекомендации по архитектуре или подходы к созданию решения для веб-приложений с использованием LINQ to SQL?

Ответы [ 2 ]

16 голосов
/ 07 мая 2010

Боюсь, вы действительно видели слишком упрощенные примеры. LINQ to SQL (System.Data.Linq) - ваш уровень DAL. Классы, которые генерирует L2S - это ваш домен (но не путайте с Domain-Driven Design ). Кроме того, вы все еще можете написать свой бизнес-уровень.

Я всегда стараюсь предотвратить утечку LINQ to SQL DataContext на уровень представления (ваше веб-приложение). Так что он не должен быть в состоянии создать или зафиксировать DataContext. Также не следует возвращать IQueryable<T> объекты на уровень представления. ИМО бизнес-уровень должен иметь полный контроль над временем жизни DataContext (единица работы) и формой SQL-запросов.

Однако, есть несколько вкусов. Некоторые люди стремятся ослабить эти ограничения. Другие даже идут намного дальше. Это зависит от вашего вкуса и размера приложения. Чем больше приложение, тем больше оправданно добавлять слои абстракции.

Запрещая IQueryable s и другим данным, связанным с данными, покидать бизнес-уровень, вы столкнетесь с некоторыми интересными проблемами. Например, уровень представления должен указывать бизнес-уровню, как сортировать результаты. Хотя вы можете позволить уровню представления сортировать результаты самостоятельно, это будет означать, что вам придется получать все данные из базы данных и страницы на уровне представления, что приведет к очень плохо работающей системе. Есть несколько решений этой проблемы. Во всех случаях вам нужно будет сообщить бизнес-уровню, как сортировать результаты для вас. Решения могут быть найдены здесь в SO при поиске LINQ динамической сортировки . Я сам написал такое решение, здесь .

Другая проблема, которую запрещает IQueryable s покидать ваш BL, заключается в том, что доменные объекты часто не могут покинуть ваш BL. Большинство ваших объектов домена LINQ to SQL будут содержать лениво загруженные свойства (например, коллекции для других объектов домена). Однако когда DataContext контролирует бизнес-уровень, он будет удален, прежде чем вы вернете результаты на уровень представления. Когда презентация обращается к ленивому загруженному свойству, возникает исключение, потому что DataContext уже удален. Когда вы располагаете DataContext на своем бизнес-уровне, это поведение, конечно, «разработано». Разрешение слою представления загружать ленивые свойства означает, что BL теряет контроль над запросами, отправляемыми в базу данных, таким образом теряя контроль над производительностью.

Чтобы решить эту проблему, вы должны вернуть объекты передачи данных (DTO) из BL на уровень представления. DTO будет содержать только данные и нет внутренних DataContext, а также не будет загружено ленивых свойств. DTO может быть специально отформатирован под текущий запрос. Конечно, DTO сами приводят к накладным расходам на кодирование, поэтому размер вашей системы и требования к производительности должны это оправдывать. Чтобы облегчить себе задачу, я склонен использовать статические методы проекции в DTO. Хотя это не соответствует принципу разделения интересов , я считаю, что это очень практичное решение. Посмотрите, например, на это CustomerDTO:

public class CustomerDTO
{
    public int CustomerId { get; set; }
    public string Name { get; set; }
    // City is flatterned from Address.City.
    public string City { get; set; }

    internal static IQueryable<CustomerDTO> AsDTO(IQueryable<Customer> customers)
    {
        return
            from customer in customers
            select new CustomerDTO()
            {
                CustomerId = customer.Id, 
                Name = customer.Name,
                City = customer.Address.City
            };
    }
}

Этот DTO определяет внутренний метод AsDTO, который может преобразовать коллекцию объектов домена Customer в коллекцию CustomerDTO DTO. Это значительно упрощает преобразование объектов домена в DTO. Посмотрите, например, на этот метод BL:

public static CustomerDTO[] GetCustomersByCountry(string country)
{
    using (var db = ContextFactory.CreateContext())
    {
        IQueryable<Customer> customers =
            (from customer in db.Customers
            where customer.Address.Country == country
            orderby customer.Name, customer.Id);

        return CustomerDTO.AsDTO(customers).ToArray();
    }
}

Приятной особенностью этого подхода является то, что когда вы посмотрите на запрос SQL, вы увидите, что из базы данных будут извлечены только идентификатор клиента, имя и город из таблицы адресов. Это связано с тем, что метод AsDTO переводит один IQueryable в другой, позволяя LINQ to SQL выполнять всю операцию в базе данных.

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

4 голосов
/ 07 мая 2010

LINQ to SQL - это доступ к БД в реализации DAL, если вы хотите разделить DAL и BLL. Если у вас есть менее сложное веб-приложение (и вы никогда не собираетесь переключать серверные части БД), то вы можете обойтись без явного DAL / BLL и делать все в коде. LINQ to SQL отлично подходит для операций только для чтения, но для реализации операций записи требуется немного больше работы.

...