Spring Data JDBC能够支持DDD中聚合概念,实际支持ER中星型模型,在DDD中聚合根实体代表整体概念,映射到数据表中就是星型模型中的主表,整体和部分的关系一般是一对一和一对多关系,其中一代表整体这一方,不会存在多对一或多对多关系,因为整体只能有一个。
首先看看一对一关系,一对一关系体现在对象和数据表两个方面,先看看你对象的一对一关系,假设有一个Order订单,其中包含了对地址Address的一对一关系,Order代码如下:
@Table("ordersample") public class Order { @org.springframework.data.annotation.Id public Integer Id; //代表一对一的关系 public Address address;
..
}
Address的代码如下:
public class Address { @org.springframework.data.annotation.Id public Integer Id; public String street; public String zipcode; }
一对一关系中,对象的类中都必须有一个主键标识,如上面的Id,Order和Address都有一个唯一标识Id,注释都是@org.springframework.data.annotation.Id,注意不是javax.persistence.Id,后者是JPA的主键标识。
那么,对应的数据表结构应该怎样呢?我们可以从运行出错的信息中一窥究竟。
先把仓储接口写好:
public interface OrderRepo extends CrudRepository<Order, Integer>
再写好测试代码:
Order order = new Order(); Address address = new Address(); address.street = "a street"; address.zipcode = "123456789"; order.address = address; orderRepo.save(order);
试验运行的时候会提示SQL出错,数据表结构没有创建:
Table "ORDERSAMPLE" not found; SQL statement:
INSERT INTO ordersample () VALUES () [42102-197]
Order对应的数据表ordersample没有创建,注意这里数据表名称如果不指定ordersample,默认是order会引起冲突,order是保留名称。
ordersample数据表主要是一个自增主键:
CREATE TABLE ordersample ( id Integer IDENTITY PRIMARY KEY, );
在application.properties填入配置:
logging.level.sql=true
database=h2 spring.datasource.schema=classpath*:schema.sql spring.h2.console.enabled=Debug
这里需要导入schema.sql用来创建数据表结构。将ordersample数据表结构SQL放入schema.sql即可。
再次运行测试程序:
Caused by: org.h2.jdbc.JdbcSQLException: Table "ADDRESS" not found; SQL statement:
INSERT INTO address (street, zipcode, ordersample) VALUES (?, ?, ?) [42102-197]
这里SQL语句已经显示Address对应的address数据表结构:
CREATE TABLE address ( id Integer IDENTITY PRIMARY KEY, ordersample Integer, street VARCHAR(80), zipcode VARCHAR(80) );
这里的id对应类Address中@Id标注的主键,street和zipcode也是对应类Address的字段,比较特殊的是ordersample,这个显然是一个代表关系的外键,指向ordersample数据表,也就是说,数据表之间表达一对一关系的方式是通过外键引用实现的。
假设订单Order中存在OrderItem:
@Table("ordersample") public class Order { @org.springframework.data.annotation.Id public Integer Id; //1:1 public Address address; //1:N public Collection<OrderItem> items;
类Order中使用集合Collection表示多个OrderItem,OrderItem的代码:
public class OrderItem { public String productVO; public int qty; }
注意到,在1:N关系中,多方这里无需使用@Id唯一主键,从DDD角度来看,OrderItem其实是一个值对象,值对象与实体的区别就是没有唯一标识。OrderItem对应的数据表结构:
CREATE TABLE order_item ( ordersample_key Integer IDENTITY PRIMARY KEY, product_vo VARCHAR(80), qty INTEGER, ordersample INTEGER );
我们注意到,Spring Data JDBC默认使用ordersample_key作为order_item表的主键,因为OrderItem对象是值对象,但是数据表需要主键,因此使用ordersample_key,同时外键ordersample指向同名的主表ordersample,这是数据表的1:N的方式。
源码
Spring Data JDBC主题