2010-12-07 45 views
1

最近,我们的EF架构已经迁移到此。我正在寻找关于如何最好地改变它(或不是)的建议。数据架构

我们有一个“数据”项目,该项目包含了我们DataModel.EDMX文件,它返回我们的实体对象一个Context.cs类一起:

public static DataModelEntities getContext() {   
    return new DataModelEntities(); 
} 

然后,我们创建一个“业务”项目,该项目包含近EF生成的类的副本。例如,如果我们有一个客户表,我们创建了一个CustomerBO类来保存属性:

public class CustomerBO { 
    public int customerId {get;set;} 
    public string firstName {get;set;} 
    public string lastName {get;set;} 
    public int orderCount {get;set;} 
} 

我们在理论上可以使用由EF创建Customer类,但我们不这样做,因为它通常包含如果我们最终将其序列化并通过网络传递,则会有很多额外的东西。

在我们的CustomerBO类中,我们有检索/保存数据的方法。例如,getCustomerList方法:

public static List<CustomerBO> getCustomers() { 
    using (var context = Context.getContext()) { 
     var lst = from c in context.Customers 
        select c; 

     // Wrap the EF results to a List<Customer> 
     return toCustomerList(lst); 

    } 
} 

/// Wraps a queryable object to a List<Customer> 
private static List<CustomerBO> toCustomerList(IEnumerable<Customer> queryCustomerData) { 
    var data = from c in queryCustomerData 
       select new CustomerBO() { 
        customerId = c.customerId, 
        firstName = c.firstName, 
        lastName = c.lastName, 
        orderCount = c.CustomerOrders.Count() 
       }; 

    return data.ToList(); 
} 

我们始终确保使用toCustomerList方法将所有数据返回到GUI。它向我们保证会设置任何自定义属性,如orderCount,并且不要求开发人员记住将这些自定义属性添加到主EF查询中。

总的来说,设计是坚实的,并已解决了多年来我们碰到的许多问题。但是,有一个特别的问题困扰我。我们称之为“业务”层,但我们在其中有一些“查询”逻辑。有没有更好的方法来设计这个模式,以符合既定的模式,并仍然达到相同的结果?

回答

1

您的设计看起来相当合理。

我会做一个评论 - 尽量不要使用静态辅助方法进行数据检索,并尽量不要将它们放在DTO类(例如CustomerBO)中。

为什么不在数据项目中创建存储库?

称它为CustomerRepository,它的响应能力是将业务查询转换成EF查询,并将结果投影到DTO中。

更简单的方法 - 你保持你的DTO的好和薄,他们不应该有任何逻辑。另外,如果您了解延迟执行和延迟加载的风险,则可以从您的存储库返回IQueryable<T>,并从业务层返回具体集合(例如ICollection<T>) - 这是我们为实现最大灵活性所做的工作。所有的逻辑(查询/业务)都在我们的业务/服务层。

您的具有查询逻辑的“业务”层没有错 - 我们也是这样做的。我们在业务层建立查询并传递到我们的存储库。

您可以使用的唯一模式是CQRS - 您可以在“命令”中分隔“查询”。

然而这是一个非常繁琐/涉及的架构。

我认为将您的DAL代码抽象到存储库中就足够了。

HTH。

EDIT

这里是一个非常简单的IQueryable<T>库例如:

CustomerRepository

public class CustomerRepository 
{ 
    private MyDataContext _ctx; 

    public CustomerRepository(MyDataContext ctx) 
    { 
     this._ctx = ctx; 
    } 

    public IQueryable<Order> FindOrders() 
    { 
     return _ctx.Orders; 
    } 
} 

CustomerDomainService

public class CustomerDomainService 
{ 
    public ICollection<Order> GetOrdersForCustomer(int customerId) 
    { 
     // You should in reality use interfaces and dependency injection here.. 
     CustomerRepository repo = new CustomerRepository(new MyContext()); 
     var orders = repo.FindOrders().Where(x => x.CustomerId == customerId).ToList(); 
    } 
} 

正如我所说,要非常小心与IQueryable存储库。只有推迟查询到您的域名服务,而不是更晚。此外,只有您的域名服务应该引用存储库。

因此,您的演示文稿请​​求来自您的域服务的数据,该数据将针对存储库进行查询并返回结果。

+0

因此,当我使用CustomerRepository时,基本上是将getCustomers()方法从我的DTO类移出到CustomerRepository类中 - 仍然是静态方法?我有兴趣了解更多关于你对Iqueryable/ICollection观点的信息 - 你知道一篇好文章吗? – bugfixr 2010-12-09 22:59:08

0

我想你可以使用EF实体(如果你说你的版本几乎是重复的),并且只需用你需要的额外功能对它们进行部分的类化处理,比如通过线路发送它们的序列化。 我没有看到任何问题。每次你更新你的edmx你的部分类将保持不变。