C# 业务对象之间的关系过于易访问,且资源极度匮乏。我怎样才能解决这个问题?

C# 业务对象之间的关系过于易访问,且资源极度匮乏。我怎样才能解决这个问题?,c#,business-objects,data-access,C#,Business Objects,Data Access,首先,这似乎是一个很长的问题。我不认为是。。。代码只是我目前所做工作的概述。这感觉不对劲,所以我正在寻找建设性的批评和警告,寻找我能做什么的陷阱和建议 我有一个包含业务对象的数据库。 我需要访问父对象的属性。 我需要通过业务对象维护某种状态 如果你看一下这些类,我认为访问修饰符是不对的。我认为它的结构不是很好。大多数关系都是用公共属性建模的。SubAccount.Account.User.ID延迟加载-除非访问AccountCollection对象,否则不要在用户内部创建AccountColle

首先,这似乎是一个很长的问题。我不认为是。。。代码只是我目前所做工作的概述。这感觉不对劲,所以我正在寻找建设性的批评和警告,寻找我能做什么的陷阱和建议

我有一个包含业务对象的数据库。
我需要访问父对象的属性。
我需要通过业务对象维护某种状态


如果你看一下这些类,我认为访问修饰符是不对的。我认为它的结构不是很好。大多数关系都是用公共属性建模的。SubAccount.Account.User.ID延迟加载-除非访问AccountCollection对象,否则不要在用户内部创建AccountCollection对象。或者,您可以让它与用户同时检索帐户集合,并避免1+9000次数据库访问

有更多的选择性收集检索方法(例如,你打算对9000名用户做什么?如果你需要他们的所有信息,这并不是浪费)

具有较小的“摘要”对象,用于下拉列表和查找等长列表-这些对象是简单的只读业务对象-通常只包含少量信息,可用于检索完整的对象


如果您正在进行分页,用户列表是否加载一次并存储在web服务器中,然后从缓存副本进行分页,还是每次都从数据库中加载集合并由控件进行分页?

这个答案最终包含了许多热门词标题。希望我能解释每一个,以及为什么它适用于这里。我认为我在下面介绍的每个概念都值得考虑——它们并不总是适用的,但我发现它们都是我个人在思考系统结构时觉得有价值的东西

单一责任 首先思考每个对象的责任——它的工作是什么?一般来说,一旦你决定为每门课做一份工作,你会发现一个更好的设计。目前,您的很多类都做得太多了,它们持有的逻辑实际上应该作为服务存在

上面的第一个示例是您的用户类:

public class User { 

   public string ID {get;set;} 
   public string FirstName {get; set;} 
   public string LastName {get; set;} 
   public string PhoneNo {get; set;} 

  public AccountCollection accounts {get; set;} 

  public User { 
     accounts = new AccountCollection(this); 
  } 

  public static List<Users> GetUsers() { 
     return Data.GetUsers(); 
  } 

} 
公共类用户{
公共字符串ID{get;set;}
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共字符串PhoneNo{get;set;}
公共帐户集合帐户{get;set;}
公共用户{
账户=新账户集合(此);
} 
公共静态列表GetUsers(){
返回Data.GetUsers();
} 
} 
为什么这提供了一个从数据源检索用户的方法?该功能应该转移到用户服务中

这方面的另一个关键示例是子帐户上的GenerateReport方法—不要将报表生成逻辑与子帐户对象紧密绑定。将其拆分将为您提供更大的灵活性,并减少对子帐户的更改,从而打破报告逻辑

延迟加载 再次看看你的用户类-为什么它在实例化时加载所有用户帐户?是否每次与用户一起工作时都会使用这些对象

通常最好引入延迟加载-仅在需要时检索帐户。当然,有时您希望立即加载(如果您知道您很快就会想要对象,因此希望减少数据库访问),但您应该能够针对这些异常进行设计

依赖注入 这种情况从延迟加载点和单一责任点开始。你有很多硬编码的引用,比如你的数据类。这使得您的设计更加严格——重构数据访问以引入延迟加载,或者改变检索用户记录的方式,因为现在许多类都直接访问数据访问逻辑,这就更加困难了

摘要对象 给Cade Roux一个小提示——我从来没有听说过术语Digest Object,通常称之为轻量级DTO

正如Cade所说,如果您所做的只是显示一个绑定到唯一ID的用户名组合框,那么就没有理由检索包含完整功能用户对象的富列表

引入一个仅存储非常基本的用户信息的轻量级用户对象

这也是引入服务/存储库抽象和某种依赖注入的另一个原因。当您将数据检索从实际对象中封装出来,并且不严格绑定到数据访问实现时,更改从数据存储中检索的对象的类型会变得容易得多

得墨忒耳定律 您的对象对彼此的内部结构了解得太多。允许用户向下钻取帐户,然后再钻取子帐户,这混淆了每个对象的责任。当您不应该设置子帐户信息时,您可以从用户对象设置子帐户信息

我一直在与这个原则斗争,因为钻研继承权似乎很方便。问题是,它将阻止您对每个对象的封装和角色进行有问题的思考


也许不要向用户公开Account对象,而是尝试引入属性和方法来公开Account对象的相关成员。查看GetAccount方法,而不是Account属性,这样您就可以强制自己使用Account对象,而不是将其视为用户的属性。

好的,现在只需对代码进行快速注释

public class SubAccount {
   public Account account {get; set;}    //this is public so that my Data class can access the account, to get the account's user's ID.

    public SubAccount(Account account) {
        this.account = account;  
    }
    [snip]
}
如果将
帐户
属性中的setter传入ctor,然后分配给backing字段,则您甚至不需要该属性中的setter

通过在ctor上传递属性来设置属性是一个很好的实践,但是如果您的
public class SubAccount {
   public Account account {get; set;}    //this is public so that my Data class can access the account, to get the account's user's ID.

    public SubAccount(Account account) {
        this.account = account;  
    }
    [snip]
}