n 层应用程序中的实体框架 - 延迟加载与急切加载模式

发布于 2024-08-28 12:10:06 字数 1106 浏览 8 评论 0原文

这个问题让我睡不着觉,因为一年以来我一直在努力寻找解决方案,但……我的脑海里仍然没有发生任何事情。也许你可以帮助我,因为我认为这是一个很常见的问题。

我有一个 n 层应用程序:表示层、业务逻辑层、模型层。为简单起见,假设我的应用程序在表示层中包含一个允许用户搜索客户的表单。现在,用户通过 UI 填写过滤器并单击按钮。发生了一些事情,请求到达表示层,调用 CustomerSearch(CustomerFilter myFilter) 之类的方法。该业务逻辑层现在保持简单:在模型上创建查询并返回结果。

现在的问题是:你如何面对加载数据的问题?我的意思是业务逻辑层不知道该特定方法将仅由该表单调用。所以我认为它不知道请求表单是否只需要返回 Customer 对象或带有链接的 Order 实体的 Customer 对象。

我尝试更好地解释: 我们的表格只想列出按姓氏搜索的客户。与订单无关。因此,业务逻辑查询将类似于:

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

现在可以正常工作了。两天后,您的老板要求您添加一个表单,让您可以像其他人一样搜索客户,并且您需要显示每个客户创建的订单总数。现在我想重用该查询并添加附加(包含)订单并返回该订单的逻辑。

你会如何提出这个请求?

这是我自现在以来最好的(我认为)想法。我想听听你的意见: 我在 BLL 中的 CustomerSearch 方法不会直接创建查询,而是通过组成 ObjectQuery 的私有扩展方法,例如:

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

但这

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

并不能说服我,因为它看起来太复杂了。

谢谢, 马可

This questions doesn't let me sleep as it's since one year I'm trying to find a solution but... still nothing happened in my mind. Probably you can help me, because I think this is a very common issue.

I've a n-layered application: presentation layer, business logic layer, model layer. Suppose for simplicity that my application contains, in the presentation layer, a form that allows a user to search for a customer. Now the user fills the filters through the UI and clicks a button. Something happens and the request arrives to presentation layer to a method like CustomerSearch(CustomerFilter myFilter). This business logic layer now keeps it simple: creates a query on the model and gets back results.

Now the question: how do you face the problem of loading data? I mean business logic layer doesn't know that that particular method will be invoked just by that form. So I think that it doesn't know if the requesting form needs just the Customer objects back or the Customer objects with the linked Order entities.

I try to explain better:
our form just wants to list Customers searching by surname. It has nothing to do with orders. So the business logic query will be something like:

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

now this is working correctly. Two days later your boss asks you to add a form that let you search for customers like the other and you need to show the total count of orders created by each customer. Now I'd like to reuse that query and add the piece of logic that attach (includes) orders and gets back that.

How would you front this request?

Here is the best (I think) idea I had since now. I'd like to hear from you:
my CustomerSearch method in BLL doesn't create the query directly but passes through private extension methods that compose the ObjectQuery like:

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

and

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

but this doesn't convince me as it seems too complex.

Thanks,
Marco

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

彡翼 2024-09-04 12:10:16

我同意 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;
    }
}

I would agree with the comment from Hightechrider in reference to using DTOs, however you have a valid question with regard to business entities.

One possible solution (I'm using something along these lines on a project I'm developing) is to use DTOs that are read-only (at least from the presentation layer perspective. Your query/get operations would only return DTOs, this would give you the lazy loading capability.

You could setup your business layer to return an Editable object that wraps the DTO when an object/entity is updated/created. Your editable object could enforce any business rules and then when it was saved/passed to the business layer the DTO it wrapped (with the updated values) could be passed to the data layer.

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;}
}

This gives you the ability to enforce if the user can get editable objects from the business layer as well as allowing the business object to enforce if the user has permission to edit specific properties of an object. A common problem I run into with the domain I work in is that some users can edit all of the properties and others can not, while anyone can view the values of the properties. Additionally the presentation layer gains the ability to determine what to expose as editable to the user as dictated and enforced by the business layer.

Other thought I had is can't your Business Layer expose IQueryable or take standard expressions as arguments that you pass to your data layer. For example I have a page building query something like this:

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;
    }
}
乖乖兔^ω^ 2024-09-04 12:10:15

考虑将表示层和业务层之间的接口迁移到 DTO,例如:- http://msdn.microsoft.com/en-us/magazine/ee236638.aspx

像 Automapper 这样的东西可以减轻与迁移到 DTO 相关的大部分痛苦,并且迁移将明确您可以做什么以及不能处理查询的结果,即如果它位于 DTO 上,则加载它,如果不是,则需要不同的 DTO。

您当前的计划听起来表示层和数据层之间的耦合过于紧密。

Consider moving to DTO's for the interface between the presentation layer and the business layer, see for example:- http://msdn.microsoft.com/en-us/magazine/ee236638.aspx

Something like Automapper can relieve much of the pain associated with moving to DTOs and the move will make explicit what you can and cannot do with the results of a query, i.e. if it's on the DTO it's loaded, if it's not you need a different DTO.

Your current plan sounds a rather too tightly coupled between presentation layer and data layer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文