1

这个问题不让我睡觉,因为一年以来,我试图找到一个解决方案,但是...在我的脑海中仍然没有发生任何事情。可能你可以帮助我,因为我认为这是一个非常普遍的问题。n层应用程序中的实体框架 - 懒惰加载与急切加载模式

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

现在的问题是:您如何面对加载数据的问题?我的意思是业务逻辑层不知道那个特定的方法会被这个表单调用。所以我认为它不知道请求表单是否只需要客户对象或客户对象与链接的订单实体。

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

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

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

感谢, 马尔科

回答

1

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

像Automapper东西可以缓解很多与移动相关的疼痛到DTOs,这一举动将明确你可以做什么,不能做什么查询的结果,也就是说,如果它在DTO上被加载,如果它不是你需要一个不同的DTO。

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

+0

感谢您的非常非常快速的答案。所以你认为这是一个在演示层而不是业务实体中使用DTO的情况? 谢谢 Marco – Marconline 2010-04-10 00:02:28

+0

听起来好像您的应用程序正在接近它值得的大小/复杂性点。在转向DTO时总是有一个权衡,因为它们总体上增加了复杂性,但像Automapper这样的工具可以减少它变得有价值的点。 – 2010-04-10 00:36:49

+0

感谢您的建议。我会绝对检查DTO和Automapper。再次感谢你。 – Marconline 2010-04-10 09:07:51

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

感谢您的建议!幸运的是,我没有授权问题,但这对其他项目来说是一个很好的解决方案。关于将查询(作为表达式)传递给BL:我不太喜欢它,但可能这对我来说只是一个样式问题。我希望表示层尽可能的可读性和可读性。即我喜欢看到类似GetCustomersByCountry和GetCustomersByCity的东西,而不是“通用”GetCustomers(查询),但是 - 再次 - 我认为这只是一个sylistic问题。 – Marconline 2010-04-10 09:13:42