Entity Framework 数据访问层(DAL),业务逻辑层(BLL)与仓储模式的结合。

3
我正在尝试构建一个具有UI、BLL和DAL的三层架构。我正在使用带有存储库模式的Entity Framework。
我的问题是:Entity Framework生成的实体是否应该作为我的BLL的一部分,还是只是DAL对象?
问这个问题的原因是因为它感觉像是在重复编写代码。例如:我有一个DAL.CatEntity,它是直接从我的数据库中由Entity Framework生成的。这很好。然后,我使用我的存储库(它是我的DAL的一部分)将数据拉入DAL.CatEntity中。然后,我在我的BLL中使用这个DAL.CatEntity,提取出它的所有数据,并将其转换成BLL.Cat。然后,我在我的UI层中使用这个BLL.Cat。
以下是一些超级简化的代码。
BLL
public Cat GetCat(string catName){
    CatEntityRepository _repository = new CatEntityRepository;
    Cat cat = null;
    CatEntity catEntity = _repository.GetSingleCat();
    cat = ConvertToCat(catEntity);
    return cat;
}

private Cat ConvertToCat(CatEntity entity){
    return new Cat(){
        Name = entity.Name,
        Color = entity.Color,
        //....
    }
}

UI:

public ActionResult method(){
    Cat cat = BLL.GetCat();
    //......
}

似乎没有必要同时拥有Cat和CatEntity。我能否只使用我的EntityFramework实体作为BLL的一部分,同时将Repository用作我的DLL?
谢谢。

2
你最好使用像AutoMapper这样的东西,而不是创建自己的自定义映射类。这样可以减少很多工作量。 - Erik Funkenbusch
3个回答

3
最终,你所做的一切都取决于你自己。大多数应用程序介于理想和可怕之间,在实用和实际的领域内。
你需要做的是看看你的应用程序的复杂性。它越复杂,受益于高度分离的程度就越大。通常,应用程序的简单性并不能证明创建清晰层所需的大量工作是值得的。
话虽如此,在大量小到中等复杂度的应用程序中,你可以有效地将实体视为业务对象。特别是,如果你使实体成为POCO并成为你的业务层的一部分,然后在你的EF DAL中使用这些实体,那么它可以非常高效。
然而,我始终建议不要直接将业务或数据对象发送到UI。你应该有专门的UI对象,在业务和UI之间进行翻译。
我认为,在可能更改数据访问方法时保持业务和数据之间的强分离是最有意义的。例如,如果你认为可能会改用Web服务来获取数据,而不是直接使用EF。此外,关注点的强分离对于单元测试非常有帮助。

很好的观点。我的应用程序将包括一个网站和一个独立的Web服务。这两者都需要访问相同的BLL。此外,未来可能会改为使用Web服务来访问我的数据。听起来这种轻微的代码重复在未来可能会得到回报。 - Josh Claxton
@Kiwi:从存储库返回 ef 实体并在外部进行转换是最糟糕的方法之一。如果您想要进行转换,请在存储库内部进行,并公开转换后的对象。请参考 Mark Seemann 的《.NET 依赖注入》一书。 - Wiktor Zychla

2

如果你觉得你在重复编写代码,那么你可能不需要一个服务层,你的EF实体可以作为业务模型。这通常适用于简单的CRUD应用程序,在这种情况下,你不需要一个业务层。


1

另一种方法不是在两种对象之间进行转换,而是将您的领域实体创建为接口,并根据接口编写存储库。

这样,您可以同时烘制两个蛋糕。您不需要将数据层实体转换为业务逻辑层实体,同时也不会弄乱层次结构(因为您的存储库不使用具体的数据层类型)。

这种方法非常有用,但很少被描述。


无转换意味着您的代码更清洁、更快。而且,您仍然保留了不针对具体类编码的好处。区别在于,使用您的方法,您会针对bll实体编写bll层代码。而在我的方法中,您会针对接口编写代码。 - Wiktor Zychla
@MystereMan:你能详细解释一下吗?为什么你认为有依赖关系?我没有看到。域接口在域层中定义,位于数据层下面,比bll层低两层。数据层完全不知道bll层的存在。 - Wiktor Zychla
@MystereMan:这个可能存在的问题是正确的。我不认为它会很严重,因为你使用接口传递对象,但我也不否认这个问题的存在。然而,复制领域实体的问题在于它很昂贵。从这两种可能性中,一个人只能选择自己喜欢的。 - Wiktor Zychla
@kiwi:就像您的 EF 类是自动生成的一样,您的接口也可以生成。重复不是问题,问题在于分离。您只有两个选择。要么复制实体,要么将它们隐藏在接口后面。不做任何事情的剩余选项不是一个选择,因为您的 EF 类在业务层中,这违反了存储库模式。您说您不会做两次,那么为什么需要存储库呢?而不是直接针对 EF 编写 BLL 代码?如果您误用存储库,那么为什么还需要它呢? - Wiktor Zychla
@WiktorZychla - 我的存储库访问我的数据库并返回EF对象。然后在我的BLL中操作此EF对象,以返回可由UI使用的BLL对象。这样做有什么误用存储库模式的地方吗?如果我的存储库开始返回BLL对象,则我已经破坏了UI->BLL->DAL层次结构,其中我的DAL引用了BLL。 - Josh Claxton
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接