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

时间:2010-04-09 23:44:38

标签: entity-framework architecture lazy-loading eager-loading n-layer

这个问题让我睡不着,因为有一年我试图找到一个解决方案,但......我脑子里还没有发生任何事情。可能你可以帮助我,因为我认为这是一个非常普遍的问题。

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

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

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

(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)

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

谢谢, 马可

2 个答案:

答案 0 :(得分:1)

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

像Automapper这样的东西可以减轻与移动到DTO相关的大部分痛苦,并且移动将明确表示您可以和不能对查询结果做什么,即如果它是在DTO上加载的话,如果它不是你需要的话不同的DTO。

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

答案 1 :(得分:1)

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