Entity Framework в n-многоуровневом приложении - отложенная загрузка и ускоренная загрузка - PullRequest
1 голос
/ 10 апреля 2010

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

У меня n-слойное приложение: уровень представления, уровень бизнес-логики, уровень модели. Предположим для простоты, что мое приложение содержит на уровне представления форму, которая позволяет пользователю искать клиента. Теперь пользователь заполняет фильтры через пользовательский интерфейс и нажимает кнопку. Что-то происходит, и запрос поступает на уровень представления к методу, подобному CustomerSearch(CustomerFilter myFilter). Этот уровень бизнес-логики теперь упрощает задачу: создает запрос к модели и возвращает результаты.

Теперь вопрос: как вы сталкиваетесь с проблемой загрузки данных? Я имею в виду, что уровень бизнес-логики не знает, что именно этот метод будет вызываться только этой формой. Поэтому я думаю, что он не знает, нужна ли запрашивающей форме только объекты Customer назад или объекты Customer со связанными объектами Order.

Я пытаюсь объяснить лучше: наша форма просто хочет перечислить клиентов, ищущих по фамилии. Это не имеет ничего общего с заказами. Таким образом, запрос бизнес-логики будет выглядеть примерно так:

(from c in ctx.CustomerSet
where c.Name.Contains(strQry) select c).ToList();

теперь это работает правильно. Спустя два дня ваш начальник попросит вас добавить форму, которая позволит вам искать клиентов, подобных другим, и вам нужно будет показать общее количество заказов, созданных каждым клиентом. Теперь я хотел бы повторно использовать этот запрос и добавить часть логики, которая присоединяет ( включает в себя ) ордера и возвращает их.

Как бы вы ответили на этот запрос?

Вот лучшая (я думаю) идея, которая у меня была с тех пор. Я хотел бы услышать от вас: мой метод CustomerSearch в BLL не создает запрос напрямую, а проходит через закрытые методы расширения, которые составляют ObjectQuery, например:

private ObjectQuery<Customer> SearchCustomers(this ObjectQuery<Customer> qry, CustomerFilter myFilter)

и

private ObjectQuery<Customer> IncludeOrders(this ObjectQuery<Customer> qry)

но это не убеждает меня, поскольку кажется слишком сложным.

Спасибо, Marco

Ответы [ 2 ]

1 голос
/ 10 апреля 2010

Я бы согласился с комментарием Hightechrider в отношении использования DTO, однако у вас есть действительный вопрос в отношении бизнес-структур.

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

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

public class Editable
{
    //.......initialize this, other properties/methods....

    public bool CanEdit<TRet>(Expression<Func<Dto, TRet>> property)
    {
        //do something to determine can edit
        return true;
    }

    public bool Update<TRet>(Expression<Func<Dto, TRet>> property, TRet updatedValue)
    {
        if (CanEdit(property))
        {
            //set the value on the property of the DTO (somehow)
            return true;
        }
        return false;
    }

    public Dto ValueOf { get; private set;}
}

Это дает вам возможность принудительно установить, может ли пользователь получать редактируемые объекты из бизнес-уровня, а также разрешить принудительное применение бизнес-объекта, если у пользователя есть разрешение на редактирование определенных свойств объекта. Распространенная проблема, с которой я сталкиваюсь в домене, в котором я работаю, заключается в том, что некоторые пользователи могут редактировать все свойства, а другие - нет, а любой может просматривать значения свойств. Кроме того, уровень представления получает возможность определять, что следует показывать пользователю как доступное для редактирования, как предписано и применяется бизнес-уровнем.

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

public class PageData
{
    public int PageNum;
    public int TotalNumberPages;
    public IEnumerable<Dto> DataSet;
}

public class BL
{
    public PageData GetPagedData(int pageNum, int itemsPerPage, Expression<Func<Dto, bool>> whereClause)
    {
        var dataCt = dataContext.Dtos.Where(whereClause).Count();
        var dataSet = dataContext.Dtos.Where(whereClause).Skip(pageNum * itemsPerPage).Take(itemsPerPage);

        var ret = new PageData
                        { 
                          //init this
                        };

        return ret;
    }
}
1 голос
/ 10 апреля 2010

Рассмотрите возможность перехода к DTO для интерфейса между уровнем представления и бизнес-уровнем, см., Например: - http://msdn.microsoft.com/en-us/magazine/ee236638.aspx

Что-то вроде Automapper может облегчить большую часть проблем, связанных с переходом в DTO, и этот шаг сделает явным то, что вы можете и не можете делать с результатами запроса, т.е. если он загружен в DTO, если он вам не нужен другое DTO.

Ваш текущий план звучит слишком тесно между уровнем представления и уровнем данных.

...