这是人们通常设计课程的方式吗? 一个类= 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的情况下将这些类加载/保存回数据库的最佳做法是什么?一个简单的代码示例将非常有用
答案 0 :(得分:10)
我建议阅读Martin Fowler的Patterns of Enterprise Application Architecture,它有几种类和表之间的映射模式。
答案 1 :(得分: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;
}
答案 2 :(得分:2)
在大多数情况下,我倾向于将表映射到实体,但这并不是一个很难的规则。有时,有些情况下,特定实体的存储库最好处理围绕特定实体的一般问题,这意味着它将交叉处理其他表,而不需要将这些表特别需要作为实体存在。
我从不做的事情(除非需要与实体一起检索依赖数据的非常具体的计划情况),将实体或实体集合设置为另一实体的属性。相反,该实体将通过其ID发现,该ID可以是父实体的属性,也可以通过与父实体相关的相关存储库发现。
如果我需要将子实体或另一个实体的实体捆绑在一起,我将使用“info”帮助程序类来汇总所有必需的数据。例如,如果我有一个实体类Widget
并且它有一个子Part
个对象的集合,那么我将创建一个包含WidgetInfo
实例的Widget
类一个属性和一组Part
个对象作为另一个属性。
这样,所有实体类都保持尽可能轻量级,并且永远不会假设需要加载相关数据。此外,它还可以保持存储库模型的清晰,而不会让您陷入混乱的ORM区域,如果您在实体类上创建子对象集合,通常就是这种情况。如果你这样做没有 ORM,那么你最终会遇到什么时候加载孩子的混乱问题,以及何时假设孩子已经或者没有被加载。
答案 3 :(得分:1)
我不会说我每桌总是有课,特别是当你有多对多的关系时。根据你上面的表格,我会有两个班级...我不知道你为什么同时拥有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; }
}
答案 4 :(得分:1)
除非您的用户是数据录入员,否则通常认为从用例/用户故事设计类更好。即使数据库已经存在。
原因?用户最终可以轻松地假设他们的工作是运用软件,而不是期望软件帮助他们完成工作。
显然,他们需要在某个时刻相交。我同意福勒的书是一个很好的起点。但我认为他会强化这一观点。
如果您想要一个可以帮助您同时获得类和数据库的建模透视图,请考虑对象角色建模。
答案 5 :(得分:0)
如果您打算使用对象关系映射(ORM),这可能会影响您的表设计。例如,Hibernate不喜欢同一树中的混合继承映射策略。
由于您明确表示不会使用ORM,因此您可以遵循传统的数据库设计原则。这通常意味着从每个类的一个表开始,标准化为第三范式(read about database normalization here),然后进行非规范化以满足性能约束(read about denormalization here)。
关于如何在不使用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;
}
您没有指定使用哪种语言,但无论您是否认为DAO this example using Java generics有用。
答案 6 :(得分: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这样的库,该文档也可以帮助您查看在将类映射到数据库表时可能需要考虑的一些选项。
答案 7 :(得分:0)
这种数据库到类的观点方法很可能会引导您快速启动大量代码。但是,这段代码的很大一部分可能没有任何用处或需要一些严重的突变。换句话说,您可能会构建与您的显示和工作流程不匹配的特定类。
首先,请考虑您的应用,用户的需求,一般工作流程等。实际上提出了一些看起来可行的东西(即模拟您的显示器)。
专注于在需要之后使用显示器和存储(db设计)建模所需的类。您可能只有几个直表课程,因为您的大多数课程自然会为您的显示提供解决方案。
祝你好运。