说我有3层
第1层:WPF项目(包含:xaml,viewmodels,mvvm框架)
第2层:业务逻辑层(包含:普通c#类)
第3层:实体框架(包含:存储库/数据访问类)
当你不想将你的DAL(第3层)暴露给视图(第1层)时 你如何很好地实现业务逻辑层? 我很难在BLL对象和DAL实体之间来回放置值。
你可以帮忙吗?答案 0 :(得分:4)
实体框架在“断开连接”模型中不能很好地工作。除非事情发生变化,否则我从未能够轻松地将其发挥得很好。
您可以在第2层中使用AutoMapper来创建ViewModel以呈现给第1层,但是您仍然需要将更改发送回第3层,这可能很痛苦。
答案 1 :(得分:3)
如果你只是开发一个在可预见的情况下不会改变的小应用程序,那么现在就做任何最快的事情。如果您想要一个长期可维护的应用程序,那么让我提出以下内容。
这种垂直层方法的问题在于,只要您在视图中需要某些内容,就必须将其添加到业务层(即使业务层不关心它)和数据层。这要求您的业务层看起来像1)数据的UI视图2)数据的业务视图和3)数据的数据库表示。那和/或你需要在层之间进行大量的映射。所有这些都淡化了业务层表示业务逻辑的实际目的。接下来发生的事情是,所有业务逻辑都迁移到事务方法(也可能是静态方法),只是改变数据对象的状态。如果您的问题域只是CRUD而没有复杂的逻辑,那就没有什么不妥了。使用复杂的逻辑,这样的业务方法可能会变得非常棘手,甚至会产生不确定的结果(因为“字段”的复杂相互依赖性可能是矛盾的,很难解决)。
假设您有复杂的逻辑,数据的用户视图和数据的业务表示通常是非常不同的,因此UI视图最终会有专门的数据模型。如果我是你,我只是接受这个并使用简单版本的CQRS原则。也就是说,UI视图的数据来自与执行业务操作的位置不同的位置。在您的情况下,我可能在您的DAL中有一个EF模型,它只为您的UI视图提供服务,并为他们提供他们所需的内容(无论是数据库视图,存储过程还是预编译的报表)。然后创建一个单独的EF模型,仅为您的业务实体提供服务。然后,当您准备执行实际的业务操作时,UI的viewmodel操作方法可以从业务EF模型加载业务对象(或者更好的是,从执行此操作的业务层调用对象工厂)并对其执行适当的操作业务对象。请注意,我在这里也假设您的数据库是高度关系的(主要是第二和第三范式)并且您已经开始使用EF。
我不会尝试将您的View模型变为业务逻辑。这使您的业务逻辑不容易在其他平台或应用程序(如Web)上重用。 MVVM应该只为UI提供服务。在我看来,V(视图)代表用户看到和操作的内容。 M(模型)表示用户在该视图上选择 的内容 。 VM(视图模型)在两者之间进行转换。然后,您的程序应该采用用户的验证选择(UI模型)并从中提取所需的数据以执行适当的业务操作。
答案 2 :(得分:2)
不要将所有DAL暴露给视图层,只需在所有层之间交换域对象(EF对象)。结构可能类似于以下内容:
因此,您的所有图层都将断开连接;但他们将共享相同的域对象。在现实世界中,您可以通过为所有层共享的Entity Framework实体创建单独的dll来实现类似的结构。请注意,ObjectContext只对DAL可见(默认情况下,实体和对象上下文在同一个dll中生成,您需要将其分成两个dll)。
答案 3 :(得分:1)
您的ViewModels
是您在MVVM中的应用程序,因此他们应该通过您的Repository类或业务逻辑(直接或间接使用您的验证类)处理数据访问等事务。
如果您不想直接引用类,请使用Interface
但请注意,您需要有一些方法将继承的类传递给ViewModel。我曾经做过一个项目,我们有一个共享接口库,比如IRepository
接口,所有东西都是用MEF导入/导出的,所以这些层没有直接相互引用。
最终(简化)布局是:
模型 - >包含普通数据对象,可以对自己的数据(长度,最小值/最大值等)进行简单验证,但不进行任何高级验证或业务逻辑。没有引用任何其他库。
普通 - >包含接口,实用程序和其他常用共享类。仅参考了模型库。
DAL - >包含基于Common库中的存储库接口的数据访问和存储库。引用接口定义和实用程序的公共库,以及模型库,因为它包含在数据访问调用中使用或返回的数据模型
ViewModels - >包含应用程序和业务逻辑。引用公用事业和接口的通用,以及数据模型的模型
客户 - >包含视图。引用模型和ViewModel,因此它可以为两种对象类型编写DataTemplates
答案 4 :(得分:1)
除了Daryal的回答之外,您可以将BL中的业务对象定义为POCO,并在DAL层中使用EF从中读取或将它们保存到数据库中。
如果您在BL中定义了类似于存储库的界面(或工作单元,无论您给它命名的任何命名),并在DAL中实现该界面,那么您只需要一点DI来获取实例存储库类,无需始终引用DAL。它对我来说就像一个魅力。
答案 5 :(得分:0)
实体框架本身可以用作“逻辑层”。
使用组合技术可能有一定道理。
但是,我认为其中一些是微观的。图书馆,设计为单独使用,除非另有明确的组合和在他们的网站上提到。祝你好运。
答案 6 :(得分:0)
我是第二个daryal,我已经在一些项目中实现了这一点。将POCO用作业务对象是绝对可以的。
另一种方法,而不是创建2个项目(一个用于DB上下文,一个用于实体)是仅使用一个DAL / DATA项目并在BLL中引用它。然后在BLL中继承POCO类并在UI层中使用该类。以下是基本示例代码:
// assume this is EF generated POCO
namespace Owner.Project.Data{
public partial class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
}
// this is manually created class in BLL
using Owner.Project.Data;
namespace Owner.Product.Business{
public class StoreProduct : Product {
public bool Add (string productName){
// TODO - add product using EF as you normally do
}
}
}
现在您可以在UI项目中引用BLL并在那里使用StoreProduct类。要实现松耦合模式,当然您也可以从IStoreProduct接口继承StoreProduct类,并在UI或Web服务中使用它,但这是另一个主题。