2

这就是通常设计课程的方式吗?一个类 = 1 个表。包含另一个表的外键的表怎么样?

假设我有以下内容:

PersonTable
---------------
person_id
name

PersonMapTable
---------------
map_id
type_id (fk)
person_id

PersonTypeTable
-------------------
type_id
description
parent_type_id

AddressTable
-------------------
address_id
address1
address2
city
state
zip

AddressMapTable
-----------
address_map_id
address_id
person_id

好的做法是否包括为每个表创建一个类?如果是这样,在没有 orm 的情况下将此类类加载/保存回数据库的最佳实践是什么?一个简单的代码示例将非常有帮助

4

8 回答 8

10

我建议阅读 Martin Fowler 的企业应用程序架构模式,其中有几种类和表之间的映射模式。

于 2009-04-04T18:09:07.813 回答
3

我不认为每个表一个对象一定是一个好的设计。很难给出一刀切的规则,但对象可以更丰富、更细粒度。由于不适用于对象的原因,可以对数据库进行非规范化。在这种情况下,您将拥有比表格更多的对象。

您的案例将包括 1:1 和 1:m 关系:

public class Person
{
    // 1:m
    private List<your.namespace.Map> maps; 
}

public class Map
{
    // 1:1
    private your.namespace.Type;
}
于 2009-04-04T18:05:46.370 回答
2

在大多数情况下,我倾向于将表映射到实体,但这不是硬性规则。有时,在某些情况下,特定实体的存储库最好处理围绕特定实体的一般问题,这意味着它会因此交叉处理其他表,而这些表不需要作为实体存在。

不做的事情(除非在非常具体的计划情况下,总是需要使用实体检索依赖数据),将实体或实体集合设置为另一个实体的属性。相反,该实体将可以通过其 ID 发现,该 ID 可以是父实体的属性,也可以通过与父实体相关的关联存储库发现。

在我需要将另一个实体的子实体或多个实体捆绑在一起的情况下,我将使用“信息”帮助器类将所有必需的数据汇集在一起​​。例如,如果我有一个实体类Widget并且它有一个子Part对象的集合,那么我将创建一个WidgetInfo类,该类将包含作为属性的Widget实例和Part作为另一个属性的对象集合。

这样,所有实体类都尽可能保持轻量级,并且永远不会假设需要加载依赖数据。此外,它还可以保持存储库模型的清洁,而不会强迫您进入混乱的 ORM 领域,如果您在实体类上创建子对象集合,通常会出现这种情况。如果你在没有ORM 的情况下这样做,那么你最终会遇到一个混乱的问题,即何时加载子节点,以及何时假设子节点已加载或尚未加载。

于 2009-07-15T16:22:23.670 回答
1

我不会说我总是每张桌子都有课,尤其是当你有多对多的关系时。根据您上面的表格,我将有 2 个课程...我不确定为什么您同时拥有 id 和 person_type_id,对我来说它们是相同的,但这里是课程。

Person
{
   public int Id { get; set; }

   public string Name { get; set; }

   public List<PersonType> { get; set; }
}

PersonType
{
   // I would discourage from using Type as property name as it is a keyword...
   public string [Type] { get; set; }
}
于 2009-04-04T18:07:13.557 回答
1

除非您的用户是数据输入员,否则通常认为从用例/用户故事设计类会更好。即使数据库已经存在。

原因?用户很容易最终假设他们的工作是使用软件,而不是期望软件帮助他们完成工作。

显然,它们需要在某个点相交。我同意福勒的书是一个很好的起点。但我认为他会加强这一观点。

如果您想要一个可以帮助您正确获取类和数据库的建模视角,请考虑对象角色建模。

于 2009-07-15T01:19:42.590 回答
0

如果您计划使用对象关系映射 (ORM),这可能会影响您的表设计。 例如, Hibernate不喜欢在同一棵树中混合继承映射策略。

由于您明确指出您不会使用 ORM,因此您可以遵循传统的数据库设计原则。这通常意味着从每个类一个表开始,规范化为第三范式(在此处阅读有关数据库规范化的信息),然后进行非规范化以满足性能限制(在此处阅读有关非规范化的信息)。

关于如何在不使用 ORM 的情况下加载和保存对象的问题,一种常见的策略是使用数据访问对象(DAO)。这是一个简单的例子:

public interface ICustomerDao
{
  public void insert(Customer customer) throws CustomerDaoException;
  public void update(long id, Customer customer) throws CustomerDaoException;
  public void delete(long id) throws CustomerDaoException;
  public Customer[] findAll() throws CustomerDaoException;
  public Customer findByPrimaryKey(long id) throws CustomerDaoException;
  public Customer[] findByCompany(int companyId) throws CustomerDaoException;
}

您没有指定您使用的是哪种语言,但无论如何您可能会发现这个使用 Java 泛型实现 DAO 的示例很有用。

于 2009-07-17T13:27:24.490 回答
0

好的做法是否包括为每个表创建一个类?如果是这样,在没有 orm 的情况下将此类类加载/保存回数据库的最佳实践是什么?

您正在使用 ORM。您正在将对象映射到关系表。您是否使用预先构建的库来这样做是您的决定。如果你不这样做,你实际上将自己实现一个,尽管可能没有现有 ORM 的所有花里胡哨。

两种最常见的方法是 ActiveRecord 模式和 Data Mapper 模式。每个都有其优点和缺点。

使用 ActiveRecord 模式,您可以定义其属性为您定义表列的类。此类的每个实例对应于数据库中的一行,通过创建(并保存)一个新实例,您可以在数据库中创建一个新行。更多信息可在此处获得: http ://en.wikipedia.org/wiki/Active_record_pattern

在 Data Mapper 模式中,您为每个表定义表对象,并编写将表的列分配给现有类的映射器函数。SQLAlchemy 默认使用这种模式(尽管有 ActiveRecord 类型扩展模块,它使 SQLAlchemy 的功能适应不同的接口。关于这种模式的简要介绍可以在 SQLAlchemy 的文档中找到:http ://www.sqlalchemy.org/docs/ 05/ormtutorial.html(从头开始阅读,但不包括标题为“以声明方式同时创建表、类和映射器”的部分;该部分解释了使用 SQLAlchemy 的 ActiveRecord)。

ActiveRecord 模式更易于设置和使用,并为您提供明确代表数据库的类,这在可读性方面具有优势。作为附带的好处,ActiveRecord 类的声明性质有效地充当数据库模式的清晰和直接的文档。

Data Mapper 模式在数据如何映射到类方面为您提供了更大的灵活性,因此您不必拘泥于表和类之间或多或少的一对一关系。它还将您的持久层与您的业务代码分开,这意味着您可以在以后根据需要更换其他持久性机制。这也意味着您可以更轻松地测试您的类,而无需设置数据库来支持它们。

有关 SQLAlchemy 映射器配置的更深入讨论,请查看http://www.sqlalchemy.org/docs/05/mappers.html。即使您不打算使用像 SQLAlchemy 这样的库,文档也应该可以帮助您了解在将类映射到数据库表时可能需要考虑的一些选项。

于 2009-07-17T14:10:27.497 回答
0

这种从 DataBase 到 Class 的方法很可能会引导您快速编写大量代码。然而,这段代码的很大一部分可能没有任何用处或需要一些严重的突变。换句话说,您可能会构建与您的显示和工作流程不匹配的特定类。

首先,考虑您的应用程序、用户的需求、一般工作流程.. 等等实际上想出一些看起来可行的东西(即模拟您的显示器)。

专注于您需要使用显示器的类,并根据这些需求为您的存储建模(数据库设计)。很有可能您将只有少数几个直桌课程,因为您的大多数课程自然会倾向于为您的显示器提供解决方案。

祝你好运。

于 2009-07-21T14:12:22.070 回答