繁体   English   中英

连接C#中最佳实践的类

[英]Class linking best practices in C#

首先,EF不是我们开发环境的选项,所以请不要“只使用EF”答案......

我认为这是一个相当标准的困境,所以我确信大多数专业人士都必须采取一种方式,我只是没有偶然发现...所以我在这里希望你们都能告诉我它是什么。

假设您有以下数据库表:

tblCompanies 
ID 
NAME

tblDepartments 
ID 
COMPANY_ID 
NAME

tblEmployees
ID 
DEPARTMENT_ID 
FIRSTNAME 
LASTNAME

...在代码中的类中表示这个的最佳方法是什么?

我认为最好的方法是这样的:

public class Company
{
     public int ID { get; set; }
     public string Name { get; set; }
     public List<Department> Departments { get; set; }
}

public class Department
{
     public int ID { get; set; }
     public string Name { get; set; }
     public List<Employee> Employees { get; set; }
}

public class Employee
{
     public int ID { get; set; }
     public string FirstName { get; set;}
     public string LastName { get; set; }
}

我相信这是对此的“OOP正确方法”。 然而,似乎总是发生的事情是这样的:

public class Department
{
     public int ID { get; set; }
     public string Name { get; set; }
     public int CompanyID { get; set; }
     public List<Employee> Employees { get; set; }
}

...主要是因为当你从数据库中提取一个部门时,你只会拥有公司ID,而不是完全填充公司类实例所需的所有其他属性。

(我在这里使用了一个漂亮的例子,但我在当前项目中实际处理的那个有3个字段用于将数据链接在一起所以想到在几个类中拥有相同的3个字段对我来说似乎不对)

这些场景是否有最佳实践 尽管我不喜欢只是出于懒惰而将相同数据存储在多个类中的想法,但我也不喜欢只填充其中一个字段的类的实例,因为这是我当时的所有内容。 。

这是一个常见问题,也是ORM试图解决的问题。 根据您的需求约束条件 ,确保它不是一件容易的事。

保留一份信息只有两个基本选项。 懒惰地按要求加载数据或者将其全部加载(Greedy load)。 否则你必须复制数据。

使用延迟加载,您基本上可以进行设置,以便在导航到属性时调用数据库并获取加载表示您正在访问的属性的实体所需的信息。 需要注意的棘手部分是SELECT N + 1问题。 当您最终迭代一组父实体并在每个子实体上触发延迟加载时遇到此问题,从而导致对数据库的N + 1次调用以加载一组实体(1)及其子项(N)。

贪心负载基本上表示加载您需要的所有内容。 ORM(它们工作的地方)很好,因为它们通过LINQ处理许多细节,并创建可以高性能和可维护的解决方案,通常还允许您操纵Greedy和Lazy Loading的使用。

另一个重要的问题是多对多的关系。 您需要确保不进行循环初始化,并获得循环依赖的所有包袱。 肯定有更多我错过了。

在我的拙见中,我不太确定有最好的做法 ,因为有些做法很糟糕 - 没有什么是完美的。 您可以:

  1. 开始滚动自己的对象关系映射器, 允许您删除重复的ID

  2. 使用更轻的ORM框架来处理其中一些, 使您可以摆脱重复的ID

  3. 创建专门的查询以加载数据聚合, 使您可以摆脱重复的ID (* cough * DDD)

  4. 只需像上面提到的那样保留ID的重复,而不必担心在您的域中创建显式关系模型。

可以根据自己的约束选择最佳选择。 这是一个很深刻的话题,我的经验是有限的... 所以我要说的很多盐

我不认为有这种事情的“最佳实践”手册,当然这取决于你的课程将如何使用。 但根据我的个人经验,我最终采用了这种方法:

public class Company
{
   public int ID { get; set; }
   public string Name { get; set; }

   public IEnumerable<Department> GetDepartments()
   {
      // Get departments here
   }
}

public class Department
{
   public int ID { get; set; }
   public string Name { get; set; }
   protected int CompanyID { get; set; }

   private Company _Company;
   public Company Company
   {
      get
      {
         // Get company here
      } 
   }

   public IEnumberable<Employee> GetEmployees()
   {
      // Get employees here
   }
}

public class Employee
{
   public int ID { get; set; }
   public string Name { get; set; }
   protected int DepartmentID { get; set; }

   private Department _Department;
   public Department Department
   {
      get
      {
         // Get department here
      } 
   }

   public IEnumberable<Employee> GetEmployees()
   {
      // Get employees here
   }
}

在某些情况下,我将类的一些“导航”属性publicpublic (如CompanyID和DepartmentID),以防止实例化新类以获取已经加载的值。

正如其他人所说,你也可以模拟“延迟加载”,但这需要你的一些额外努力。

我认为这取决于要求。 您是否需要向上遍历(从部门获取公司,从员工获取部门等)。 如果你这样做,那么你最好提供一种方法。 理想情况下,这将是公司或部门属性,当然你不希望得到你真正不需要的数据,所以你可能会保留一个私人公司ID,并有一个公共getCompany函数查询数据。

我相信这不是一个真正的OOP问题,在你的情况下,你只有一个数据库模型(类中的数据库表示),它不包含任何逻辑,所有类都用作结构,这是映射你的正确方法数据库到类 - 结构。 因此,在您的下一个代表程序逻辑的模块中,您必须将数据库模块映射到包含逻辑的实际类(我的意思是实现它的方法),当然如果您确实需要它们。 因此,在我看来,OO问题应该在您的应用程序的逻辑部分。 另一方面,您可以查看nhibernate以及如何在其中完成映射,它将为您提供bes数据库模型实现的提示。

我相信这就是你的类在NHibernate中的样子:

public class Company
{
     public int ID { get; set; }
     public string Name { get; set; }
     public IList<Department> Departments { get; set; }
}

public class Department
{
     public int ID { get; set; }
     public string Name { get; set; }
     public Company Company { get; set; }
     public IList<Employee> Employees { get; set; }
}

public class Employee
{
     public int ID { get; set; }
     public string FirstName { get; set;}
     public string LastName { get; set; }
     public Department Department { get; set; }
}

请注意,有一种方法可以从Employee导航到Department,从Department导航到Company(除了您已经指定的内容)。

NHibernate具有各种功能,可以使它正常工作。 而且效果非常非常好。 主要技巧是运行时代理对象以允许延迟加载。 此外,NHibernate支持许多不同的方式来急切和延迟加载,正是你想要的方式。

当然,你可以在没有NHibernate或类似ORM的情况下获得这些相同的功能,但为什么不使用功能丰富的主流技术而不是手工编写自己的功能差的自定义ORM?

还有另一种选择。 创建一个'DataController'类来处理对象的加载和“memoization”。 dataController维护[CompanyIDs,Company objects]和[DepartmentIDs,Department objects]的字典。 加载新的部门或公司时,您在此DataController字典中保留一条记录。 然后,当您实例化新的Department或Employee时,您可以直接设置对父对象的引用,也可以使用Lazy [Company / Department]对象并使用lambda(在构造函数中)设置它,这将保持对象的范围DataController没有直接在对象内引用它。 有一点我忘了提到,如果找不到特定的ID,你也可以在查询数据库的字典的getter / get方法中放置逻辑。 将所有这些结合使用可以使您的类(模型)非常干净,同时对于何时/如何加载数据仍然相当灵活。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM