客户单击项目详细时,会跳转到项目详细页面。用户单击红框中的加号,页面弹出选择标签页面。用户单击待选标签中的标签,当前标签会被保存到数据库中。前端
固然,项目标签与项目之间是多对多的关系,也就是说,一个项目能够有多个标签,一个标签对应多个项目,整体来讲,它们之间是多对多的关系。数据库
多也是相对的多,就像导读中的项目和项目标签同样。这是从宏观上来讲的多对多,但从微观上来看,其内部仍是一对多的关系。一个项目能够有多个项目标签,一个项目标签能够对应多个项目。既然对各自来讲,都是一对多的关系,为何不这样写呢:json
// 项目表 @Entity @Table(name = "zq_project") public class Project extends BaseObj { /** * 項目标签 */ @ManyToOne @JoinColumn(name = "attach_id") private List<DataDict> tagss; } //项目标签表 @Entity @Table(name = "core_data_dict", uniqueConstraints = {@UniqueConstraint(columnNames = {"tenant_id", "code"}, name = "uk_dd_tid_code")}) public class DataDict extends ToString{ /** * 項目 */ @ManyToOne @JoinColumn(name = "attach_id") private List<Project> projectList; }
而是这样书写方式呢?session
/** * 添加项目标签,若是是标签来源于数据字典,则能够直接读取数据字典 */ @ManyToMany(fetch = FetchType.EAGER) @Fetch(FetchMode.SELECT) @JoinTable( name = "zq_project_tags", joinColumns = {@JoinColumn(name = "project_id")}, inverseJoinColumns = @JoinColumn(name = "tag_code") ) @JSONField(serialize = false) private List<DataDict> tagList;
由于这样书写,hibernate会根据项目和数据字典(项目标签放在数据字典表中)生成一个中间表,如图所示:框架
为何不采用第一种方式呢?
一、第一种方式扩展性很差,破坏框架结构,为何这么说?maven
项目标签放置在数据字典中,换句话,数据字典所存储的数据集不会常常改变。就像咱们的新华字典,不会时常作版本更新。于是,相似于项目标签,数值型的单位呀、系统标量等,这些数据都不会时常改变。ide
并且,如今的项目都采用maven构建,什么是maven项目呢?不少博客都有详细介绍,我只作简单地介绍。maven是项目对象模型(POM),举一个简单的例子,咱们在不使用maven建立项目时,每每须要拷贝jar包到项目中。然而,咱们使用maven建立项目时,就会建立一个pom文件。咱们在pomp文件中作配置,若是须要新的jar包,咱们直接使用<dependence>...</dependence>模块化
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency>
固然,引用jar包是一回事,还有模块化构建项目。咱们常常分模块构建项目,好比信息发布一个模块,核心层一个模块,自定义业务层一个模块。各个模块之间就像是Java同样,具备继承和关联关系。子pom文件可使用父pom的全部jar包。如图所示:fetch
层级很是严格,即使在同一个项目不一样的模块中,咱们若是想要调用另一个模块的类时,也须要用dependency来引用其模块。好比,咱们想要在platform-custom层调用platform-core层的类,咱们须要在platform-custom的pom文件中写入依赖:spa
<dependency> <groupId>com.zfounder.platform</groupId> <artifactId>platform-core</artifactId> </dependency>
可是,项目表是自定义业务范畴的,是在platform-custom模块中的,而数据字典是属于platform-core模块的。由于platform-core的pom没有依赖platform-custom模块,于是,数据字典没法调用platform-custom模块中的项目类,如图所示:
于是,若是咱们采用这种方式建立多对多的关系,会破坏maven结构或者框架结构。
二、对于数据库的维护性很差。
对于项目来讲,相同项目标签的可能有数条项目的记录,可是,每一个项目都是惟一的,一个项目应该有多个标签,但如今的问题是,同一个项目的编号不一样了,由于不一样的项目标签,这就破坏了数据库的惟一性。
针对以上两种状况,咱们应该使用中间表,来建立多对多的关系。如图所示:
这样简洁明快,也便于往后的维护工做。
一、用户和角色之间的关系,一个用户能够有多重角色,一个角色能够对应多个用户。
二、既然说到了角色,天然说到角色所能管理的权限,好比当用户登陆,根据用户的角色,须要展现哪些页面,能够操做该页面的哪些按钮,等等。这些都放在资源表中。如图所示:
三、项目和图片的关系,一个项目有不少张图片,可是一张图片也能够被多个项目使用。
四、。。。。
中间表通常都涉及两个字段,字段分别引用两张表的主键。
咱们在点击保存项目标签时,心想咱们点击一次,保存一次,而项目类中项目标签对象是一个集合对象,咱们应该建立这个集合,而后拿到前端传
过来的项目标签的code值(数据字典对应的是code值),经过数据字典的事务方法获取这个数据字典对象,再判断该对象的父类是否是项目标签。由于数据字典存储不少类字典,好比项目标签字典、单位字典、系统变量字典等等。而后保存这个数据字典,但结果事与愿违,它会覆盖数据库中原来的数据,这是更新数据,而不是保存数据,如图所示:
为何会这样,由于,其底层使用的是merge方法,如代码所示:
/** * @see com.zfounder.platform.core.dao.GenericDao#save(T) */ @SuppressWarnings("unchecked") @Override public T save(T object) { Session session = getSession(); return (T) session.merge(object); }
merger若是发现数据库存在该编号的对象,则执行update操做;若是不存在,则执行insert操做。于是,中间表,即项目标签表,已经存在该项目编号的id,因此,执行更新操做。
咱们换一种思路,首先看项目类的部分源码:
@Data @AllArgsConstructor @NoArgsConstructor @Entity @Table(name = "zq_project") public class Project extends BaseObj { /** * 项目名称 */ @Column(name = "name") private String name; /** * 录入日期 */ @Column(name = "sign_date") private Date signDate; /** * 备注 */ @Lob @Basic(fetch = FetchType.LAZY) @Column(name = "remark", columnDefinition = "mediumtext") private String remark; /** * 预算金额 */ @Column(name = "budgetary_amount", precision = 10, scale = 2) private BigDecimal budgetaryAmount; /** * 工程起始时间 */ @Column(name = "start_time") private Date startTime; /** * 工程结束时间 */ @Column(name = "end_time") private Date endTime; /** * 添加项目标签,若是是标签来源于数据字典,则能够直接读取数据字典 */ @ManyToMany(fetch = FetchType.EAGER) @Fetch(FetchMode.SELECT) @JoinTable( name = "zq_project_tags", joinColumns = {@JoinColumn(name = "project_id")}, inverseJoinColumns = @JoinColumn(name = "tag_code") ) @JSONField(serialize = false) private List<DataDict> tagList; }
由于项目标签时多对多的关系,当咱们接收到前端传过来的项目编号,并调用项目的事务的get方法,建立当前项目瞬时态的对象时。hibernate根据项目标签表中的code值,建立项目标签(数据字典)的集合对象,并填充到tagList的集合中。咱们只要在对集合对象上,添加从前端传过的code值,并经过code值建立项目标签(数据字典)的对象便可。于是,代码改为下面的方式:
这样保存就没问题了。
若是咱们掌握了最基本知识是,就能够很容易掌握其余语言了。加油,致本身。