1

这个问题让我无法入睡,因为一年以来我一直在努力寻找解决方案,但是......我的脑海里仍然没有任何事情发生。也许你可以帮助我,因为我认为这是一个非常普遍的问题。

我有一个多层应用程序:表示层、业务逻辑层、模型层。为简单起见,假设我的应用程序在表示层中包含一个允许用户搜索客户的表单。现在用户通过 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)

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

谢谢,马可

4

2 回答 2

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;
    }
}
于 2010-04-10T00:54:38.347 回答
1

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

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

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

于 2010-04-10T00:00:13.727 回答