精华内容
下载资源
问答
  • 什么是弱实体

    千次阅读 2020-05-18 20:03:34
    弱实体的相关概念 相关文章1 相关文章2 一篇比较好的讲解弱实体的博客 比如用户 和消费记录, 消费记录的 id 和 用户的...强实体和弱实体一般是 1:N 或者 1:1 的关系,弱实体依赖强实体而存在(依赖强实体的主键) ...

    弱实体的相关概念

    相关文章1

    相关文章2
    一篇比较好的讲解弱实体的博客

    比如用户 和消费记录, 消费记录的 id 和 用户的 id 做成联合主键 唯一标识消费记录 这个实体,那么 消费记录是依附于用户实体而存在的,(先有用户,才有消费记录) 所以消费记录是弱实体,而用户则是强实体。

    强实体和弱实体一般是 1:N 或者 1:1 的关系,弱实体依赖强实体而存在(依赖强实体的主键)

    展开全文
  • 数据库中,设计的ER图里面弱实体A依赖于弱实体B的话,是否需要将弱实体B中的主键放去弱实体A中充当主键
  • 目录写在最前一、 强实体与弱实体的定义1. 强实体2. 弱实体百度百科中的解释《数据库系统课程》中的解释总结起来 写在最前 数据库设计是困难的,其原因之一就在于我们很难去完全把握实体的定义。是不是实体、该不该...

    写在最前

    数据库设计是困难的,其原因之一就在于我们很难去完全把握实体的定义。是不是实体、该不该定义实体是一直困扰数据库初学者的问题,强实体、弱实体的概念同样难以理解。
    我一直深受强实体、弱实体概念的困扰,百度百科中的定义不能很好地解决我的困惑,一路学习过来,自己对强实体、弱实体的理解越来越深入,因此写下这篇文章与大家分享自己对强实体与弱实体的一些体会。如果觉得有帮助,请点赞鼓励!

    一、 强实体与弱实体的定义

    1. 强实体

    其实例的存在不依赖于任何其他实体类型的实例;有自己独立的主键,唯一性地标识它的每个实例。

    2. 弱实体

    百度百科中的解释

    一个实体对于另一个实体(一般为强实体,也可以是依赖于其他强实体的弱实体)具有很强的依赖联系,而且该实体主键的一部分或全部从其强实体(或者对应的弱实体依赖的强实体)中获得,则称该实体为弱实体。

    《数据库系统课程》中的解释

    其实例的存在依赖于其它实体类型的实例;其主键包括它所依赖的实体类型的主键。

    总结起来

    百度百科中的解释和课程中的解释都是在强调两点:
    第一点:依赖,弱实体应该依赖于强实体;
    第二点:主键,弱实体的主键应该是组合主键(其他实体的主键组成的)。

    二、 关于定义的几个疑惑

    但定义中有几个地方令我不解,我相信初学者多少也会遇到同样的问题。我总结了四点:

    什么叫“依赖”?

    以教务系统数据库为例,如果没有学校,那么学院不再是学院,学生不再是学生,课程更将不复存在,所以这些实体都依赖于其他实体,因此这些都是弱实体?但我们知道,学院、学生一般都作为强实体。因此,定义中的“依赖”指的是什么呢?

    先有鸡还是先有蛋?

    是因为一个实体的主键包括其他实体的主键而使该实体成为了弱实体,还是因为一个实体是弱实体,所以它的主键必须包括其他实体的主键?
    这是一个先鸡(弱实体)还是先蛋(组合主键)的问题。

    为什么要定义弱实体?

    我们知道,弱实体对于另一个实体具有很强的依赖联系,似乎并不是“真实”存在的事物,那么为什么我们还会有弱实体的概念,而不是直接认为实体就是强实体呢?

    什么时候需要定义弱实体?

    有时候弱实体就是需求中的实体,只是它依赖于其他实体,有时候关系也可以认为是弱实体,有时候出于设计的需要我们也会定义弱实体,那么何时需要定义弱实体?

    总结起来,以上四个问题其实是一个问题:

    怎样正确地理解强实体与弱实体的含义?

    三、 唯有实践,方出真知

    有很多事情是很难想明白的,但经过几次数据库设计实战,我发现自己或多或少地定义了一些弱实体。我选取了三个典型的例子:

    教务系统数据库设计(一)

    之后我会专门写一篇博客介绍教务系统数据库的设计过程,这里选取其中一个比较典型的部分。业务需求是这样的:

    一周有七天,每一天有11节。

    上面这句话中涉及到了几个实体?很简单吧,三个实体:周、天、节。那么它们是强实体还是弱实体呢?不好说,但是我们可以确定,概念数据模型的设计应该是这个样子:
    在这里插入图片描述
    需要勾选“Dependent”。首先回答一个问题:为什么不能是下面这个样子?
    在这里插入图片描述
    Day的主键应该是dayOfWeek,如果不用“Dependent”将Day的主键改为weekNum+dayOfWeek,我们的Day表格中只能有七行记录,也就是说对于某一个星期一,我们无法区分这是第几周的星期一!同样的道理,如果Section的主键仅仅为sectionNum,那么我们根本无法区分这一节课是哪一天的课!教务系统要有排课、选课功能,只知道第1节,但不知道是哪一天的第一节,这肯定是不可以的。

    因此,当我们想要找到某一节时,需要同时指定那一周、星期几、哪一节。比方说我可以把《数据库设计》这门课安排在第一周星期一三四节。

    在这个例子中,三个实体都是需求中明明白白告诉我们的实体,但我们将Day与Section都作为了弱实体,因为强实体的Day与Section根本无法满足需求。

    培训公司数据库设计

    业务需求是这样的:

    每位学生每期只能参加一门课程。

    言外之意,公司有很多课程。我们只分析“每位学生每期只能参加一门课程”这一需求,发现涉及到两个实体:学生、课程。所以我们或许会想当然地这样去设计数据库:
    在这里插入图片描述
    一个课程可以由多个学生选择,一个学生只可以选择一门课程。发现问题了吗?业务需求里不是说一个学生只能参加一门课程,而是说一个学生在一期只能参加一门课程!这么设计数据库是在断人家财路。因此,我们必须考虑“每期课程”这个概念:在这里插入图片描述
    看样子似乎是没问题了,但是数据库设计是不可能这么容易就没问题的。我们把每期课程都作为一个记录,那么对于课程的信息,比方说课程名称、价格、介绍,每开一期课就要向数据库中存一行记录,因此我们的数据库会出现大量冗余(也就是说不满足数据库第二范式)。因此,我们应该这样去设计数据库:
    在这里插入图片描述
    看到了吗?这里的“Record”是一个弱实体,它的主键是“学期主键+学生主键”,代表学生参加课程这一行为,抽象成为了弱实体。为什么要用学期表的主键和学生表的主键呢?因为一个学生、一个学期,那么就只能参加一门课程了,所以根据主键唯一标识每行记录的原则,应该这样去选取。课程表的主键成为了Record表的外键,课程表与Record表之间存在一对多关系。

    在这个例子中,学生、课程是业务需求描述中显而易见的实体,“期”也可以认为是比较明显的实体,但“参加”这个动词在我们的数据库中便成为了“参加记录” ,也就是Record实体。

    教务系统数据库设计(二)

    这一部分的业务需求是这样的:

    老师授课。

    似乎业务需求很简单,但事实上,多位老师可以独立上同一门课,也可以共同上同一门课。一位老师可以参与多门课的授课。真实的教务系统的确是这个样子的。一般,像马原、高数等课程是多位老师独立授课,专业核心课大多是多位老师共同为同一班级授课。那么数据库要怎样设计呢?
    在这里插入图片描述
    像这样吗?老师、课程之间建立多对多关系?不难发现,这样的多对多联系无法区分上面所说的两种授课情况。也就是说,我们必须引入第三个表,才有可能实现业务需求,两张表格是行不通的。我是这样设计的:
    在这里插入图片描述
    在课程表与老师表之间,引入了新的一张表格——排课表。一个课程可以安排多次排课,一个排课就对应一个独立的授课安排,可以由一位老师完成,也可以由多位老师完成。那么像马原授课这种多位老师独立授课的情况该如何解决呢?在排课表中,认为不同老师的马原课是同一课程(引用Course表中同一记录的主键作为外键),但是它们是不同的排课(ArangeNo不同,可能一个是1,另一个是2)。也正因如此,排课表的主键是组合主键(课程编号+排课编号,如CS163、1)。

    这个例子中,需求中并没有提“排课”这一实体,这个实体完全是我们为了满足需求而定义的,甚至它和课程表在概念上还有点关系。注意到了吗,这里的“关系”就是弱实体概念中所说的“依赖”!

    四、 对强实体与弱实体的总结

    1. 区别弱实体与强实体的关键在于主键,“依赖”的实质是主键之间的关系。所以归根到底,就一个主键之间是否有关系、主键是否是组合主键的问题。

    2. 弱实体与强实体可以相互转换,没有绝对意义上的强与弱。既然区别弱实体与强实体的关键在于主键,那么一个同样意义的表,当我给它一个编号作为主键,那么它就不是弱实体,而如果我令它的主键是组合主键,它就是弱实体。就像刚刚,我们说排课表的主键是组合主键(课程编号+排课编号,如CS163、1),所以它是弱实体,那么如果我定义排课编号是“CS16301”,而不再是“1”,那么它的主键(排课编号)就不再需要课程编号,它就成为了强实体。

    3. 弱实体也可以依赖于弱实体。就像第一个例子中的Session,它依赖于Day,Day就是一个弱实体。

    4. 弱实体与它所依赖的实体之间的关系只能是1:1或n:1。也就是说,一个弱实体实例不可能依赖于同一实体的多个实例。这个其实很好理解,因为如果弱实体实例A依赖于实例B,那么A的主键要包括B的主键,所以A当然不可以依赖于很多个B。

    5. 业务需求决定弱实体的定义,分三种情况:

      情况一、 业务需求中明确的弱实体
      情况二、 业务需求中隐含的弱实体
      情况三、 业务需求中无、但为实现业务需求不得不定义的弱实体

      如果觉得这篇文章对你有帮助,请给博主点个赞!

    展开全文
  • 请问这是弱实体吗? 平时真实的开发中弱实体应用得多不多? 问题2: 一个导师可以教导多个学生 一个学生只能有一个导师 关系{老师,学生} [color=#FF6600] 老师学生同为主键[/color] 以上关系式多值依赖?...
  • 文章目录2.1、实体类2.2、持久化字段和属性2.2.1、例子2.3、Access type (访问类型)2.3.1、默认访问类型2.3.2、显式访问类型2.3.3 内嵌类的访问类型2.3.4、内嵌类的默认访问类型和映射超类2.4、主键实体身份2.4.1...

    实体是一个轻量级持久化域对象

    主要的编程工件是实体类,实体类可以使用辅助类,这些辅助类用作帮助类或用于表示实体状态的辅助类。

    本章介绍对实体类和实体的要求。

    2.1、实体类

    • 实体类必须是Entity注解进行标记,或在XML描述符中表示为实体。
    • 实体类必须具有无参的构造方法,实体也可以具有其他构造方法,无参构造方法必须是public或protected修饰的
    • 实体必须是顶级类,枚举和接口不得指定为实体。
    • 实体类不能是final修饰的,实体类的任何方法或持久性实例变量都不得是final修饰的。
    • 如果实体实例要通过值作为传输的对象(例如,通过远程接口)传递,则实体类必须实现Serializable接口。
    • 实体支持继承、多态关联和多态查询
    • 抽象类和具体类都可以是实体。实体可以扩展非实体类以及实体类,并且非实体类可以扩展实体类。
    • 实体的持久状态有实体变量表示, 实体变量可能对应于JavaBeans属性。实体变量只能由实体实例本身直接从实体的方法内部访问,实例变量不能由实体的客户端访问,客户只能通过实体的方法(即访问getter/setter方法)或者其他业务业务方法,才能使用实体的状态。

    2.2、持久化字段和属性

    • 持久性提供程序运行时[1]^{[1]} 通过JavaBeans方式属性访问器(“属性访问") 或实例变量(“字段访问”)访问实体的持久状态。如果第2.3节”访问类型“中所述, 确定提供者对给定类或实体层次结构使用的是持久性属性还是持久性字段,还是两者的组合。

      • 术语备注:实体类的持久字段和属性在本文档中通常称为类的"属性"
    • 类的实例变量必须是private, protected或package(包可见)的修饰,而与使用字段访问还是属性访问无关,使用属性访问时,属性访问器方法必须是public或protected修饰。

    • 对于使用属性访问的持久属性,要求实体类遵循Java Beans读写属性(有Java Beans Introspector类定义)的方法签名约定。

    • 在这种情况下,对于实体类型T的每个持久属性,都有一个getter方法,getProperty和setter方法的setProperty. 对于布尔属性,可以将isProperty用作getter方法的替代名称[2]^{[2]}

    • 对于单值持久属性,这些方法签名为:

      • T getProperty()
        
        void setProperty(T t)
        
    • 备注

      • [1] : 术语"持久性提供程序运行时"是指持久性实现的运行时环境,在Java EE环境中,这可能是Java EE环境中,这可能是Java EE容器或与其集成的第三方持久性提供程序实现。
      • [2] : 具体来说,如果getX是getter方法的名称,而setX是setter方法的名称,其中X是字符串,则持久属性的名称有java.beans.Introspector.decapitalize(X)的结果定义
    • 不论实体类是否遵守JavaBeans, 都必须根据以下集合值接口之一定义集合值的持久字段和属性。上面提到的方法约定以及是否使用字段或属性访问:java.util.Collection, java.util.Set, java.util.List[3]^{[3]}和java.util.Map. 在实体成为持久化之前,应用程序可以使用集合实现类型来初始化字段或属性,一旦实体被管理(或分离),随后的访问必须通过接口进行。

      • 术语备注:除非另有说明,否则在本规范中使用术语”集合“和"集合值"来表示以上任何类型。在要区分java.util.Collection类型(或其子类型之一)的情况下,将这样标识该类型。当需要区分java.util.Map类型的集合时,术语"map"和"map collection"用于应用于java.util.Map类型的集合
    • 对于具有集合值的持久属性, 类型T必须是上述方法签名中的这些集合接口类型之一。鼓励使用这些集合类型的泛型变量(例如Set)

    • 除了返回并设置实例的持久状态外,属性访问器方法还可以包含其他业务逻辑,例如,以执行验证,当使用基于属性的访问时,持久性提供运行时将执行此逻辑。

      • 使用属性访问时,在向访问其方法添加业务逻辑时应谨慎行事。未定义持久性提供运行时在加载或存储持久性状态时调用这些方法的顺序。因此,此类方法中包含的逻辑不应依赖于特定的调用顺序。
    • 如果使用属性访问并指定了延迟提取,则便携式应用程序不应直接访问托管实例的属性方法基础的实体状态,直到持久性提供程序将其提取[4]^{[4]}

    • 如果将持久性上下文加入到事务中,则属性访问器方法引发的运行时异常会导致当前事务被标记为回滚,持久性运行时使用此类方法抛出的异常来加载或存储持久状态时,会导致持久性运行时将当前事务标记为回滚,并引发包装了应用异常的PersistenceException.

    • 实体子类可以覆盖属性访问器方法。但是可移植应用程序不得覆盖适用于实体超类的持久字段或属性的对象/关系映射的元数据。

    • 备注

      • [3] : 除非使用OrderColumn构造或使用OrderBy构造并且对列表的修改遵循指定的顺序,否则便携式应用不应期望在持久性上下文维护列表的顺序。
      • [4] : 延迟获取是对持久性提供程序的提示,可以通过Basic, OneToOne, OneToMany, ManyToOne, ManyToMany和ElementCollection批注及其XML等效项进行指定。请参阅第11章。
    • 这个持久化字段或实体的属性可能如下类型: java原生数据类型, java.lang.String, 和其他序列化类型(包含原生数据类型的包装类, java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar[5]^{[5]}, java.sql.Date, java.sql.time, java.sql.Timestamp, byte[], Byte[], char[] Character[] java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime, java.time.OffsetTime, java.time.OffsetDateTime,和用户自定实现Serializable接口类型),枚举类型,实体类型,实体的集合类型,内嵌类(请参阅2.5节),集合的基础和内嵌类型(请参阅2.6)。

    • 可以指定对象/关联映射元数据以定制对象/关系映射以及实体状态和关系的加载和存储。请参阅第11章。

    • 备注

      • [5] : 请注意,Calendar实例必须针对其映射到的类型进行完全初始化。

    2.2.1、例子

    • public class Customer implements Serializable{
        
        private Long id;
        
        private String name;
        
        private Address address;
        
        private Collection<Order> orders = new HashSet();
        
        private Set<PhoneNumber> phones = new HashSet();
        
        // 无参构造函数
        public Customer(){}
        
        
        @Id  //使用属性访问
        public Long getId(){
          return id;
        }
        
        public void setId(Long id){
          this.id= id;
        }
        public String getName(){
          return name;
        }
        public void setName(String name){
          this.name=name;
        }
        
        public Address getAddress(){
          return address;
        }
        public void setAddress(){
          this.address=address;
        }
        
        @OneToMany
        public Collection<Order> getOrders(){
          return orders;
        }
        
        public void setOrders(Collection<Order> orders){
          this.orders = orders;
        }
        
        @ManyToMany
        public Set<PhoneNumber> getPhones(){
          return phones;
        }
        
        public void setPhones(Set<PhoneNumber> phones){
          this.phones = phones;
        }
        
        // 业务方法添加一个电话号码给客户
        public void addPhone(PhoneNumber phone){
          this.getPhones().add(phone);
          //更新phone的实体实例以引用此客户
          phone.addCustomer(this);
        }
      }
      

    2.3、Access type (访问类型)

    2.3.1、默认访问类型

    • 默认情况下,单一访问类型(字段或属性访问)适用于实体层次结构。实体层次结构的默认访问类型由映射注解在未明确的指定访问类型的实体类型的属性和映射的超类的属性上的放置方式决定。如 2.2.3节所述,通过访问注解显式指定访问类型[6]^{[6]}
    • 当使用注解定义默认访问类型时,将映射注解放置在实体类的持久字段或持久属性上时,会将访问类型分别指定为基于字段或基于属性的访问。
      • 当使用基于字段的访问时,实体类的对象/关系映射注解将对实体变量进行标记, 而持久性提供程序运行时将直接访问实例变量,所有未使用Transient注解进行标记的non-transient实例变量都是持久性的。
      • 使用基于属性的访问时,实体的对象/关系映射注解[7]^{[7]}类注解getter属性访问器,并且持久性提供程序运行时通过属性访问器方法访问持久状态。所有未使用Transient注解进行标记的属性都是持久性的。
      • 映射注解不能应用于transient或Transient修饰的字段或属性上。
    • 实体层次结构中以这种方法默认访问类型的所有此类都必须在字段或属性上的注解位置上保持一致,以便在层次结构中应用单个一致的默认访问类型。 这些类使用的任何可嵌入类都将具有与层次结构的默认访问类型相同的访问类型,除非按以下定义指定了Access注解。
    • 如果无法确定默认的访问类型并且未通过注解或XML描述符显式指定访问类型,则会出现错误。 未定义将注解在实体层次结构中的字段和属性上混合放置而未明确指定Access注解的应用程序的行为。
    • 备注
      • [6] : 第12章介绍了使用XML作为替代方法以及Java语言注解和XML元素在定义默认和显式访问类型中的交互
      • [7] : 这些注解不得应用于setter方法。

    2.3.2、显式访问类型

    • 可以通过应用于该类的Access注解,为该类指定单个实体类,映射超类或可嵌入类的访问类型, 而与实体层次结果的默认设置无关,此显式访问类型规范不会影响实体层次结构中其他实体类或映射的超类的访问类型。适用以下规则:
      • 当将Access(FIELD)应用于实体类, 映射的超类或可嵌入的类时,可以将映射注解放置在该类的实例变量上,并且持久性提供程序运行时通过该类定义的实例变量访问持久性状态,所有未使用(Transient)瞬态注解进行标记的非瞬态实例变量都是持久性的,将Access(FIELD)应用于此类时,可以有选择地在该类中指定各个属性以进行属性访问。若要指定持久性提供程序运行时访问的持久性属性,必须将该属性性指定为Access(PROPERTY).[8]^{[8]} 如果将映射注解放置在未为其指定Access(PROPERTY)的类定义的任何属性上,则该行为未定义,从超类继承的持久状态将根据这些超类的访问类型进行访问。
      • 将Access(PROPERTY)应用于实体类,映射的超类或可嵌入的类时,可以将映射注解放在该类的属性上,并且持久性提供程序运行时会通过该类定义的属性访问持久状态。所有未使用Transient注解进行标记的属性都是持久性的,将Access(PROPERTY)应用于此类时,可以有选择地在该类中指定各个属性,例如变量访问。 若要指定持久性实例变量以供持久性提供程序运行时访问,则该实例变量必须指定为Access(FIELD), 如果将映射注解放置在未为其指定Access(FIELD)的类定义的任何实例变量上,则该行为未定义。从超类继承的持久状态将根据这些超类的访问类型进行访问。
      • 请注意,当将访问类型组合在一个类中时,应使用Transient注解来避免重复的持久映射

    2.3.3 内嵌类的访问类型

    • 可嵌入类的访问类型取决于实体类,映射超类或嵌入它的可嵌入类的访问类型(包括作为元素集合的成员),而与包含对象的访问类型无关,类已被明确指定或默认,可以通过如上所述的Access注解为该可嵌入类指定不同的可嵌入类访问类型。

    2.3.4、内嵌类的默认访问类型和映射超类

    • 定义在字段访问上下文和属性访问上下文中使用且其访问类型未通过Access注解或XML映射文件明确指定的可嵌入类或映射超类时,必须格外小心。
    • 应该定义此类,以使所得持久性属性的数量,名称和类型相同,而与所使用的访问类型无关。如果属性发生在同一个持久性单元内的不同访问类型的上下文中,则这个这些属性与访问类型无关的类在于元模型API结合使用时是不确定的。

    2.4、主键和实体身份

    • 每个实体都应该有一个主键

    • 必须在做完实体层次结构根的实体类上或在做为实体层次结构中所有实体类的(直接或间接)超类的映射超类上定义主键。在实体层次结构中,主键必须定义一次。

    • 主键对应于实体类的一个和多个字段或属性(“attributes”)

      • 一个简单的(即非复合的)主键必须对应于实体类的单个持久字段或属性。必须使用Id注解或id XML元素来表示一个简单的主键。参见11.1.21节。
      • 组合主键必须对应于单个持久性字段或属性,或对应于如下所述的一组此类字段或属性。必须定义一个主键类来表示一个复合主键。当数据库键由几列组成时,从主数据库进行映射时,通常会出现复合主键,EmbeddedId或IdClass注解用于表示复合主键,参见11.1.17 和11.1.22节
    • 简单主键或复合主键的字段或属性应为以下之一类型:任何java基本类型和任何基本类型的包装类类型,java.lang.String; java.util.Date; java.sql.Date; java.math.BigDecimal; java.math.BigInteger[9]^{[9]}, 如果主键是从另一个实体的主键派生的复合主键,主键可以包含一个属性,其类型为所引用实体的主键的类型,如第2.4.1节中所述。主键使用其他类型之外的实体将不可移植性,如果使用生成的主键,则仅整数类型可移植的。如果将java.util.Date用作主键字段或属性,则应将时间类型指定为DATE。

    • 以下规则适用于复合主键:

      • 主键类必须是public修饰和必须有public修饰无参构造函数。
      • 主键类的访问类型(基于字段或基于属性的访问)由作为主键的实体的访问类型确定,除非主键是嵌入式Id且指定了其他访问类型。请参见第2.3节”访问类型“。
      • 如果使用基于属性的访问,则主键类的属性必须是public或protected修饰的
      • 主键类必须实现序列化接口
      • 主键类必须定义equals和hashCode方法,这些方法的值相等的语义必须与键映射到的数据类型的数据库相等一致。
      • 组合主键必须表示并映射为可嵌入类(请参见第11.1.17节"EmbeddedId 注解"),或者必须表示id类并映射到实体类的多个字段或属性(请参见第11.1.22节 ”IdClass注解)
      • 如果将组合主键类表示为id类,则该主键类中的主键字段或属性的名称以及与该id类映射的实体类的名称必须相对应,并且他们的类型必须相同。
      • 对应于派生身份的主键必须符合2.4.1节的规则
    • 它的主键值唯一地标识了持久性上下文中的一个实体实例,并在第3章“实体操作” 中对EntityManager操作进行了标识。 应用程序不得更改主键的值[10]^{[10]}。如果发生这种情况,则行为是不确定的[11]^{[11]}

    • 备注

      • [9] : 但是,一般而言,绝不能在主键中使用近似数字类型(例如浮点型)
      • [10] : 这包括不更改作为主键的可变类型的值或不对复合主键进行分配的值。
      • [11] : 该实现可以但不要求引发异常,可移植应用程序不得依赖任何此类型特定的行为。

    2.4.1、对应于派生身份的主键

    • 当前一个实体("从属"实体)是与该实体多对一或一对一关系的所有者时,一个实体的身份可以从另一个实体("父"实体)的身份派生而来,父实体和外键将关系从依赖关系映射到父关系。
    • 如果多对一或一对一实体关系与主键属性相对应,则在不将该关系分配给实体的情况下,包含该关系的实体不能持久化,因为包含该关系的实体的身份为从引用的实体派生。[12]^{[12]}
    • 可以通过简单的主键或复合主键来捕获派生身份,如下面第2.4.1.1小节所述。
    • 如果从属实体类除具有对应于父级主键的属性外还具有主键属性,或者父级具有复合主键,则必须使用嵌入式id或id类指定从属实体的主键。当父对象具有复合主键时,父实体和从属实体都不必使用嵌入式id或都使用ID类来表示复合主键。
    • 一个从属实体可以有多个父实体。

    2.4.1.1、派生身份描述

    • 如果从属实体类使用id类表示其主键,则必须遵守以下两个规则之一:

      • id类的属性名称和从属实体类的Id属性名称必须对应如下:
        • 实体类中的id属性和id类中的对应属性必须具有相同的名称。
        • 如果实体类中的Id属性为基本类型,则id类中的对应属性必须具有相同的类型。
        • 如果实体中的Id属性与父实体存在多对一或一对一关系,则id类中的对应属性必须与父类的id类或嵌入式id具有相同的Java类型实体(如果父实体具有复合主键)或父实体的Id属性的类型(如果父实体具有简单的主键)。
      • 如果从属实体具有单个主键属性(即,关系属性),则由从属性实体指定的id类必须与父实体的主键类相同[13]^{[13]},Id注解应用于与父实体的关系
    • 备注

      • [12] :如果该应用程序没有设置与之对应的主键属性,则该属性的值可能直到将实体刷新到数据库后才可以使用。
      • [13] : 请注意,在这种情况下,遵循第一条规则作为替代是正确的。
    • 如果从属实体使用嵌入式ID表示其主键,则对应于关系数的嵌入式ID中的属性必须与父实体的主键具有相同的类型,并且必须由应用于父实体的MapsId注解指定,关系属性,必须使用MapsId 注解的value元素在关系属性所对应的嵌入式ID中指定属性的名称。如果从属实体的嵌入ID与父实体的主键具有相同的Java类型,则关系属性会将关系映射到从属实体和主键,在这种情况下MapsId 注解指定没有value元素[14]^{[14]}

    • 如果从属实体具有单个主键属性(即,关系属性或与该关系属性相对应的属性),并且父实体的主键是简单的主键,则从属实体的主键与父实体类型相同的简单主键(并且未指定EmbeddedId和IdClass)。 在这种情况下,要么(1)关联属性被注解为Id,要么(2)指定一个单独的Id属性,而关系属性被注解为MapsId(并且未指定MapsId注解的value元素)

    • 备注

      • [14] :注意父类的主键可能代表一个内嵌id或一个id类

    2.4.1.2、派生身份的映射

    • 从父实体的身份派生的主键属性由对应的关系属性映射,此关系的默认映射如2.10节中所述。如果默认映射不适用或要覆盖默认映射,则在关系属性上使用JoinColumn或JoinColumns注解
    • 如果从属实体使用嵌入的id表示其主键,则AttributeOverride注解可用于覆盖嵌入的id属性的默认映射,该默认映射不应于映射派生的标识的关系属性。提供者将与该关系对应的嵌入式Id属性视为“只读”,也就是说,在应用程序部分对它们的任何更新都不会传播到数据库。
    • 如果从属使用Id类,则可以使用Column注解覆盖不是关系属性的Id属性的默认映射。

    2.4.1.3 派生身份的例子

    • 例子1:父实体有一个简单主键

      • @Entity
        public class Employee{
          @Id 
          long empId;
          
          String empName;
          ...
        }
        
        //案例(a) 依赖实体使用 IdClass作为一个组合键
        public class DependentId{
          String name; // 匹配@Id属性的名称
          
          long emp; // 匹配@Id属性的名称和Employee 主键的类型
        }
        
        
        @Entity
        @IdClass(DependentId.class)
        public class Dependent{
          @Id
          String name;
          
          @Id
          @ManyToOne Employee emp; // join默认映射的id属性
        }
        
        // 查询语句样例
        SELECT d 
        FROM  Dependent d
        WHERE d.name='Joe' AND d.emp.empName='Sam';
        
        
        //案例(b) 依赖实体使用EmbeddedId去代表组合键
        
        @Embeddable
        public class DependentId{
          String name;
          long empPK; // 对应Employee的主键类型
        }
        
        @Entity
        public class Dependent{
         
          @EmbeddedId DependentId id;
          ...;
          // 通过join默认列来进行id属性映射
          @MapsId("empPK")   // 映射嵌入式id的empPK属性
          @ManyToOne Employee emp;
        }
          
        //查询样例
        SELECT d 
        FROM  Dependent d
        WHERE d.id.name='Joe' AND d.emp.empName='Sam';
          
        
        
    • 例子2:父实体使用Id

      • public class EmployeeId{
          String firstName;
          
         	String lastName;
          ...
        }
        
        public class Employee{
          @Id String firstName;
          @Id  String lastName;
          ...
        }
        
        // 案例(a) 依赖实体使用IdClass:
        
        public class DependentId{
          String name; // 匹配名称属性
          
          EmployeeId emp; //匹配名称属性和Employee主键的类型
        }
        
        @Entity
        @IdClass(DependentId.class)
        public class Dependent{
          @Id String name;
          @Id
          @JoinColumns({
            @JoinColumn(name="FK1", referencedColumnNmae="firstName"),
            @JoinColumn(name="FK2", referencedColumnName="lastName")
          })
          @ManyToOne Employee emp;
          
          // 样例查询
          SELECT d
          FROM Dependent d
            
          WHERE d.name='Joe' AND d.emp.firstName='Sam'
        }
        
        //案例(b) : 从属实体使用EmbeddedId, empPK属性的类型与Employee主键的类型相同。EmployeeId类需要被注解为可嵌入的,或在XML描述符中被表示为可嵌入的类。
        
        @Embeddable
        public class DependentId{
          String name;
          EmployeeId empPK;
        }
        
        @Entity
        public class Dependent{
          @EmbeddedId DependentId id;
          ...;
          @MapsId("empPK")
          @JoinColumns({
            @JoinColumn(name="FK1", referencedColumnName="firstName"),
            @JoinColumn(name="FK2", referencedColumnName="lastName")
          })
          @ManyToOne Employee emp;
        }
        //样例查询
        SELECT d
        FROM Dependent d
        WHERE d.id.name='Joe' and d.emp.firstName='Sam';
        //下面语句将会查询同样的结果
        SELECT d
        FROM Dependent d
        WHERE d.id.name='Joe' and d.id.empPK.firstName = 'Sam';
        
        
    • 例子3 父级实体使用EmbeddedId:

      • @Embeddable
        public class EmployeeId{
          String firstName;
          
          String lastName;
        }
        
        @Entity
        public class Employee{
          @EmbeddedId EmployeeId empId;
        }
        
        //案例(a)依赖实体使用IdClass
        
        public class DependentId{
          String name;  // 匹配@Id属性的名称
          EmployeeId emp; // 匹配@Id属性的名称和匹配Employee的embedded id类型
        }
        @Entity
        @IdClass(DependentId.class)
        public class Dependent{
          @Id
          @Column(name="dep_name")//默认列名被重写
          String name;
          
          @Id
          @JoinColumns({
            @JoinColumn(name="FK1", referencedColumnName="firstName"),
            @JoinCOlumn(name="FK2", referencedColumnName="lastName")
          })
          @ManyToOne Employee emp;
        }
        //样例查询
        SELECT d 
        FROM  Dependent d
        WHERE d.name='Joe', and d.emp.empId.firstName='Sam';
        
        //案例(b) 依赖实体使用EmbeddedId:
        
        @Embeddable
        public class DependentId{
          String name;
          EmployeeId empPK; //对应Employee Pk的类型
        }
        
        @Entity
        public class Dependent{
          
          //默认列表将被重写为"name"
          @AttributedOverride(name="name", column=@Column(name="dep_name"))
          @EmbeddedId DependentId id;
          ...;
          @MapsId("empPK")
          @JoinColumns({
            @JoinColumn(name="FK1", referencedColumnName="firstName"),
            @JoinColumn(name="FK2",referencedColumnName="lastName" )
          })
          @ManyToOne Employee emp;
        }
        // 查询样例
        SELECT d
        FROM Dependent d
        WHERE d.id.name='Joe' and d.emp.empId.firstName='Sam';
        // 以下查询结果一致
        SELECT d
        FROM Dependent d
        WHERE d.id.name='Joe' and d.id.empPK.firstName='Sam';
         
        
      • 例子4: 父实体有一个简单主键

        • @Entity
          public class Person{
            @Id String ssn;
            ...;
          }
          //案例(a) 从属实体具有单个主键属性,该主键属性由关系属性映射。MedicalHistory的主键的类型为字符串
          
          @Entity
          public class MedicalHistory{
            // 默认join列名将被重写
            @Id
            @OneToOne
            @JoinColumn(name="FK")
            Person patient;
            ...
          }
          
          //案例查询
          SELECT m
          FROM MedicalHistory  m
          WHERE m.patient.ssn = '123-45-6789';
          
          //案例(b) 从属实体具有与该关系相对应的单个主键属性,主键属性与父实体的主键具有相同的基本类型。这应用于关系属性的MapsId注解指定主键由关系属性映射。
          
          
          @Entity
          public class MedicalHistory{
            
            @Id String id; // 重写是不允许的
            
            //默认join列重写
            @MapsId
            @JoinColumn(name="FK")
            @OneToOne Person patient;
            ...
          }
          
          //查询示例
          SELECT m
          FROM MedicalHistory m WHERE m.patient.ssn='123-45-6789';
          
          
    • 例子 5:父实体使用IdClass, 依赖的主键类与父实体的类型一样

      • public class PersonId{
          String firstName;
          String lastName;
        }
        
        @Entity
        @IdClass(PersonId.class)
        public class Person{
          @Id String firstName;
          @Id String lastName;
          ...
        }
        
        //案例(a) 依赖实体使用IdClass
        
        @Entity
        @IdClass(PersonId.class)
        public  class MedicalHistory{
          @Id
          @JoinColumns({
            @JoinColumn(name="FK1", referencedColumnName="firstName")
            @JoinColumn(name="FK1", referencedColumnName="lastName")
          })
          @OneToOne
          Person patient;
          ...
        }
        // 示例查询
        SELECT m
        FROM MedicalHistory m WHERE m.patient.firstName='Charles';
        
        //案例(b) 依赖实体使用EmbeddedId 和 MapsId 注解,PersonId 类需要被标记为Embeddable或在XML描述符中标记为内嵌属性
        @Entity
        public class MedicalHistory{
          // 所有属性映射关系,AttributeOverride 是不允许的
          @EmbeddedId PersonId id;
          
          ...;
          @MapsId
          @JoinColumns({
            @JoinColumn(name="FK1", referencedColumnName="firstName"),
            @JoinColumn(name="FK2", referencedColumnName="lastName")
          })
          @OneToOne Person patient;
          ...
        }
        //示例查询
        SELECT m
        FROM MedicalHistory m
        WHERE m.patient.firstName = 'Charles';
        
        // 请注意,以下替代查询将产生相同的结果
        SELECT m
        FROM MedicalHistory m
        WHERE m.id.firstName = 'Charles'
          
        
    • 例子 6、父实体使用EmbeddedId, 依赖的主键要与父实体的类型一致

      • @Embeddable
        public class PersonId{
          String firstName;
          String lastName;
        }
        
        @Entity
        public class Person{
          @EmbeddedId PersonId id;
          ...;
        }
        //案例(a) 依赖类使用IdClass
        
        @Entity
        @IdClass(PersonId.class)
        public class MedicalHistory{
          
          @Id
          @OneToOne
          @JoinColumns({
            @JoinColumn(name="FK1", referencedColumnName="firstName"),
            @JoinColumn(name="FK2", referencedColumnName="lastName")
          })
          Person patient;
          ...;
        }
        
        // 案例(b) 依赖类使用EmbeddedId:
        
        @Entity
        public class MedicalHistory{
          // 所有属性必须由这个关系映射, AttributeOverride是不允许的
          @EmbeddedId PersonId id;
          ...;
           
           @MapsId
           @JoinColumns({
             @JoinColumn(name="FK1", referencedColumnName="firstName"),
             @JoinColumn(name="FK2", referencedColumnName="lastName")
           })
           @OneToOne
           Person patient;
          ...
          
        }
        

    2.5、Embeddable Classes(可嵌入类)

    • 一个实体可能使用其他细粒度类去表示实体的状态。这些类的实例并不像其实体的实例,它们没有持久化身份的标记,取而代之是只是存在部分实体的状态信息,一个实体可能用嵌入集合作为单个值 的嵌入属性。可嵌入类可能使用Map的键和值。 可嵌入类严格属于它们持有的实体上,它不会再持久实体之间共享,如果尝试去在多个实体中共享可嵌入对象将会报未定义语法错误。
    • 对于实体,可嵌入必须遵循第2.1节中指定的要求,可嵌入类不能被标记为Entity, 可嵌入类必须表标记为Embeddable 或在XML描述中进行标记,对于嵌入对象的访问类型具体描述在2.3节"访问类型"。
    • 一个可嵌入类可能用于表示另一个可嵌入类的状态。
    • 一个可嵌入类(包含带有其他可嵌入类的可嵌入类)可能包含基础类型集合或其他可嵌入类16^{16}
    • 一个可嵌入类可能包含对实体的关系或实体的集合,由于可嵌入类的实例没有持久性身份, 这个关系是从引用实体是entity,它包含可嵌入实例并不是可嵌入本身17^{17}. 一个可嵌入类可以用于作为嵌入id或作为map的键必须不能包含这个关系。
    • 额外关于可嵌入类要求和限制的描述参见2.6节
    • 备注
      • [16] : 在可嵌入类中直接或间接环形依赖是不允许的
      • [17] : 一个实体不能与另一个实体(或本身)的可嵌入类具有单向关系

    2.6、可嵌入类和基本类型的集合

    • 实体或可嵌入类的一个持久字段或属性可能对应基本类型的集合或可嵌入类(”元素集合") ,当此类集合由ElementCollection注解指定时,将通过第11.1.8节中定义的集合表进行映射。如果未为收集值的字段或属性指定ElementCollection注解(或XML等效项),则适用第2.8节的规则
    • 包含在元素集合中的可嵌入类(包含其他可嵌入类的嵌入类)不得包含元素集合,也不得包含于多对一或一个以外的实体的关系一对一的关系。可嵌入类必须在这种关系的拥有方,并且该关系必须通过外键映射进行映射。(请参阅第2.9节)

    2.7、Map集合

    • 元素和实体关系的集合可以表示为java.util.Map集合
    • 这个map的键和值都是独立,他们可以是基本类型,可嵌入类或实体
    • ElementCollection,OneToMany 和ManyToMany注解被用于指定一个map作为元素的集合或如下的实体关系:当map的值是基本类型或可嵌入类,那么用于ElementCollection注解,当map的值是实体时,那么将用OneToMany 或ManyToMany注解。
    • 表示为java.util.Map集合的双向关系仅支持在关系的一侧使用Map数据类型

    2.7.1、Map 键

    • 如果这个map键类型是基本类型,那么使用MapKeyColumn注解用于指定这个列的映射,如果MapKeyColumn注解不能指定,那么MapKeyColumn注解默认值将会应用,参见第11.1.33.
    • 如果这个map键类型是可嵌入类,那么map的键列的映射将会使用可嵌入类的默认列。(参见11.1.9节,“列注解”),AttributeOverried和AtrributeOverrides注解可以用于重写这些映射,参见11.1.4节或11.1.5节,如果一个可嵌入类用于作为map的键,一个可嵌入类必须实现hashCode和equals方法,且与数据库对应列映射一致。
    • 如果map的键类型是一个实体,MapKeyJoinColumn和MapKeyJoinColumns注解用于指定map的键。 如果引用实体是一个简单主键并且MapKeyJoinColumn注解没有指定,MapKeyJoinColumn 注解的默认值(参见11.1.35)
    • 如果在类型为java.util.Map的关系属性的声明中未使用Java泛型类型,则必须使用MapKeyClass注解指定map键的类型。
    • MapKey注解用于指定特殊情况,其中map键本身就是主键或实体的持久字段或属性,即map的值, 指定MapKey时不使用MapKeyClass注解。

    2.7.2、 Map的值

    • 当map的值类型是基本类或可嵌入类,集合表格用于映射map,如果Java泛型类型没有使用, ElementCollection注解中的targetClass元素必须用于指定map值的类型, 这个map默认列映射值衍生规则是根据CollectionTable注解定义(参见11.1.8) ,Column注解用于重写map默认的基本类型,AttributeOverride(s) 和 AssociationOverride(s)注解用于重写可嵌入类的map值映射。
    • 当map的值类型是实体,一个join表用于映射这map多对多的关系,或默认一对一单边关系。如果这个关系是多边的(一对多或多对一关系),默认情况下在实体中被映射map的值,如果java 泛型没有使用,那么OneToMany或ManyToMany中的targetEntity元素用于必须指定map的值,默认映射参见2.10节

    2.8、 对应非关系字段或属性的默认映射

    • 如果未使用第11章中定义的映射注解之一对除关系属性以外的持久字段或属性进行注解(或在XML描述符中未指定等效的映射信息),则按顺序应用一下默认映射规则:
      • 如果类型是使用Embeddable注解进行标记的类,则其映射方式与使用Embedded注解对字段或属性进行注解的方式相同,请参见第11.1.15和11.1.16节
      • 如果字段或属性的类型是以下类型之一,则其映射方式与将其注解为Basic时的映射方式相同:Java基本类型和对应的包装类, java.lang.String, java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.time.LocalDate, java.time.LocalDateTime, java.time.OffsetTime, java.time.OffsetDateTime, byte[] , Byte[], char[] Character[] 枚举和任何其他类型实现序列化(Serializable) 参见11.1.6, 11.1.18, 11.1.28和11.1.53节
    • 如果没有注解并且以上规则均不适用,则是错误的。

    2.9、实体关系

    • 实体之间的关系可能是一对一、一对多,多对一,或多对多,关系也是多态的
    • 如果两个实体之间存在关联,则以下关系建模注解之一必须应用引用实体的相应持久属性或字段:OneToOne, OneToMany, ManyToOne, ManyToMany, 对于未指定目标类型的关联(例如Java的集合类的泛型类型的地方),有必要指定作为关系目的实体16^{16}。等效的XML元素可以用作这些映射注解的替代方法。
    • 这些注解反映了关系数据库架构建模中的常见做法。使用关系建模注解可以完全默认关联到相对关联到相对数据库架构的对象/关系映射,以提供易于开发的功能。第2.10节”关系映射默认值"中对此进行了描述。
    • 关系可以是双向的或单向的,双向关系既有正侧(拥有)和反侧(非拥有),单向关系只有一个拥有方,关系的拥有方确定对数据库中关系的更新,如第3.2.4节所述。
    • 以下规则适用于双向关系:
      • 双向关系的反向必须通过使用OneToOne, OneToMany或ManyToMany注解的maptedBy元素来引用其拥有的一面,mappingBy元素指定关系的所有者的实体中的属性或字段。
      • 一对多/多对一双向关系的多面必须是拥有方,因此无法再ManyToOne注解上指定mappingBy元素。
      • 对于一对一的双向关系,拥有方对应于包含相应外键的方向
      • 对于多对多双向关系,任何一方都可能是拥有方。
    • 关系模型注解约束使用的是cascade=REMOVE规范, 这cascade=REMOVE规范应该只应用于关联指定OneToOne或OneToMany ,应用程序应用cascade=REMOVE去关联其他关系移植性不好
    • 关联被指定为OneToOne或OneToMany时还支持使用orphanRemoval选项,当orphanRemoval生效时,将发生以下行为:
      • 如果从关系中删除了作为关系目标的实体(通过将关系设置为null或从关系集合中删除实体),则删除操作将应用于孤立的实体。当移除操作应用在flush操作的时候,orphanRemoval功能适用用于其父实体主要"拥有"的实体。可移植应用程序不得不依赖于特定的删除顺序,并且不得将已孤立的实体重新分配给另一个关系,也不能尝试将其持久化。如果要孤立的实体是分离的,新增或已删除的实体,则orphanRemoval的语义不适用。
      • 如果移除操作被应用于管理源实体,移除操作将依据3.2.3规则被级联到目标的关系(所以强调的是为这个关系指定cascade=REMOVE是没有必要的)
    • 2.10节,“关系默认映射”,为实体关系定义关系的默认映射。在2.10节描述了额外映射注解(例如列和表映射注解)可能指定重写或进一步优化这个默认映射和映射的策略。
    • 此外,此规范还要支持以下替代映射策略:
      • 外键映射含义就是单边映射一对多的关系,JoinColumn注解或与之对象XML元素必须用于指定没有默认映射,参见11.1.25.
      • JoinTable注解的含义用于单边和双边映射一对一关系,双边多对一或一对多关系和单边多对一关系。JoinTable注解或与之对象XML元素必须用于指定没有默认映射,参见11.1.27.
    • 此映射注解必须指定在关系拥有的一方。映射默认值任何重写都必须与关系模型注解指定的一致。例如,多对一关系映射被指定时,对应这种关系它就不允许在外键上指定一个唯一键约束。
    • 持久层厂商处理关系的对象/关系映射时,包括实体类的元数据中指定的关系的加载和存在到数据库。以及数据库中指定的关系的参照完整性(例如,通过外键约束)
      • 请注意,正是该应用程序负责维护运行时关系的一致性,例如,当应用程序更新时,在运行时要确保双向关系的”一个"和“多个”方面彼此一致。
    • 如果没有从数据库中获取的实体的多值关系的关联实体,则持久性提供程序负责返回空集合作为该关系的值。

    2.10、默认关系映射

    • 本节定义了适用于使用OneToOne, OneToMany, ManyToOne和ManyToMany关系模型注解的映射默认值,当使用XML描述符表示关系基数时,将应用相同的映射默认值。

    2.10.1、多边OneToOne的关系

    • 假设:

      • 实体A引用了实体B的单个实例
      • 实体B引用了实体A的单个实体
      • 实体被指定为关系拥有者。
    • 如下默认映射应用:

      • 实体A映射到表名称为A
      • 实体B映射到表名称为B
      • 表A包含一个指定表B的外键,这个外键列名称由以下内容组成:关系属性的名称或实体A的字段;"_";表B主键列的名称。外键列与表B的主键具有相同的类型,并且对它具有唯一的键约束。
    • 例子

      • @Entity
        public class Employee{
          
          private Cubicle assignedCubicle;
          
          @OneToOne
          public Cubicle getAassignedCubicle(){
            return assignedCubicle;
          }
          
          public void setAssignedCubicle(Cubicle cubicle){
            this.assignedCubicle = cubicle;
          }
          ...
        }
        
        
        @Entity
        public class Cubicle{
          private Employee residentEmployee;
          
          @OneToOne(mappedBy="assignedCubicle")
         	public Employee getResidentEmployee(){
            return residentEmployee;
          }
          
          public void setResidentEmployee(Employee employee){
            this.residentEmployee = employee;
          }
          ...
        }
        
        
    • 在这个例子中:

      • 实体Employee引用了实体Cubicle的单个实例
      • 实体Cubicle引用了实体Employee的单个实体
      • 实体Employee被指定为关系拥有者。
    • 以下映射默认设置适用:

      • 实体Employee映射到表名称:EMPLOYEE
      • 实体Cubicle映射到表名称:CUBICLE
      • 表EMPLOYEE包含指定CUBICLE的外键,这个外键列名称为ASSIGNEDCUBICLE_<CUBICLE的主键>,其中CUBICLE的主键表示表CUBICLE主键列的名称。外键列与CUBICLE的主键具有相同的类型,并且对它唯一的键约束。

    2.10.2、双向ManyToOne /OneToMany 的关系

    • 假设:

      • 实体A引用了实体B的单个实体
      • 实体B引用了实体A的集合
    • 实体A必须是关系的拥有者

    • 以下映射默认设置适用:

      • 实体A映射表名A
      • 实体B映射表名B
      • 表A包含一个表B的外键, 外键列名称由以下内容组成:实体A的关系属性或字段的名称;“_" 表B的主键列名称。外键列名与表B主键类型一样。
    • 例子

      • @Entity
        public  class Employee {
          private Department department;
          
          @ManyToOne
          public Department getDepartment(){
            return department;
          }
          public void setDepartment(Department department){
            this.department = department;
          }
          ....
        }
        
        
        @Entity
        public class Department{
          private Collection<Employee> employees = new HashSet();
          
          @OneToMany(mappedBy="department")
          public Collection<Employee> getEmployees(){
            return employees;
          }
          
          public void setEmployees(Collection<Employee> employees){
            this.employees = employees;
          }
          ...
        }
        
      • 在这个例子中

        • Employee实体引用Department的实体实例对象
        • Department实体引用Employee实体的集合对象
        • Employee实体是关系拥有者。
      • 接下来应用映射默认值:

        • Employee实体映射表名EMPLOYEE
        • Department实体映射表名DEPARTMENT
        • 表EMPLOYEE包含DEPARTMENT的外键,这个外键列名为DEPARTMENT_, 表示表DEPARTMENT主键名称,外键列名和DEPARTMENT主键列具有相同的类型。

    2.10.3、单向单值关系

    • 假设:
      • 实体A引用实体B的单例
      • 实体B并没有引用实体A
    • 单边关系只有拥有的一边, 在上述情况下关系拥有者是实体A
    • 单向单值关系模型场景要么是单边OneToOne关系或单边ManyToOne关系

    2.10.3.1 单向OneToOne 关系

    • 接下来应用映射默认值:

      • 实体A映射表名A
      • 实体B映射表名B
      • 表A包含引用表B的外键, 外键列名称由以下内容组成 实体A的关系属性和字段的名称;"_";表B主键列名称。 外键列类型与表B的主键类型一样,这是一个唯一主键约束。
    • 例子

      • @Entity
        public class Employee{
          private TravelProfile profile;
          
          @OneToOne
          public TravelProfile getProfile(){
            return profile;
          }
          public void setProfile(TravelProfile profile){
            this.profile = profile;
          }
          ...
        }
        
        @Entity
        public class TravelProfile{
          ...
        }
        
        
      • 在这个例子

        • Employee实体引用TravelProfile实体单例
        • TravelProfile实体没有引用Employee实体
        • Employee是这个关系拥有者
      • 接下来应用映射默认值:

        • Employee实体映射表名EMPLOYEE
        • TravelProfile实体映射表名为TRAVELPROFILE.
        • EMPLOYEE包含TRAVELPROFILE表的外键,这个外键列名为PROFILE_, 表示TRAVELPROFILE表主键列名,外键列名与TRAVELPROFILE的主键的类型一致, 这个是唯一键约束

    2.10.3.2 、单向 ManyToOne 关系

    • 接下来应用映射默认值:

      • 实体A映射表A
      • 实体B映射表B
      • 表A包含表B的外键, 外键列名称由以下内容组成:实体A的关系属性或字段的名称;"_" ;表B主键列名, 外键列类型与表B的主键类型一样。
    • 例子:

      • @Entity
        public class Employee{
          private Address address;
          
          @ManyToOne
          public Address getAddress(){
            return address;
          }
          
          public void setAddress(Address address){
            this.address = address;
          }
          ...
        }
        @Entity
        public class Address{
          ...
        }
        
      • 在这个例子中:

        • Employee实体引用Address的实体单例
        • Address实体并没引用Employee实体
        • Employee实体使用关系拥有者
      • 接下来应用映射默认值:

        • Employee映射表名EMPLOYEE
        • Address实体映射表名ADDRESS。
        • EMPLOYEE表包含ADDRESS表的外键,这个外键列名为ADDRESS_ , 表示ADDRESS表主键列名称,外键列名和ADDRESS主键类型是一致的。

    2.10.4、双向ManyToMany关系

    • 假设:

      • 实体A引用实体B的集合
      • 实体B引用实体A的集合
      • 实体A是关系拥有者。
    • 接下来应用映射默认值:

      • 实体A映射表名A
      • 实体B映射表名B
      • 这里是一个join表关系且名称为A_B(关系拥有者写在前面)。这个join表有两个外键列。一个外键列引用表A且它有与表A主键列相同类型,这个外键名称由以下内容组成:实体B关系属性或字段名称;"_“表A主键列名称。另一个外键列引用表格B且它有与表B主键列相同类型,这个外键名称有以下内容组成:实体A关系属性或字段名称;”_";表B主键列名称。
    • 例子

    • @Entity
      public class Project{
        
        private Collection<Employee> employees;
        
        @ManyToMany
        public Collection<Employee> getEmployees(){
          return employees;
        }
        
        public void setEmployees(Collection<Employees> employees){
          this.employees = employees;
        }
        ...
      }
      
      
      @Entity
      public class Employee{
        
        private Collection<Project> projects;
        
        @ManyToMany(mappedBy="employees")
        public Collection<Project> getProjects(){
          return projects;
        }
        public void setProjects(Collection<Project> projects){
          this.projects = projects;
        }
        ...
      }
      
    • 在这个例子中:

      • Project实体引用包含Employee实体的集合
      • Employee实体引用包含Project实体的集合对象
      • Project实体是关系的拥有者
    • 接下来应用映射默认值:

      • Project实体映射表名为PROJECT
      • Employee实体映射表名为EMPLOYEE
      • join表的名称为PROJECT_EMPLOYEE( 拥有关系名称写在前面), 这个join表有两个外键列, 一个外键列引用PROJECT 表并且与PROJECT的主键的类型一致。 这个外键表名称为PROJECTS_ , 表示 PROJECT表的主键名称,另一个外键引用EMPLOYEE表并且与EMPLOYEE的主键的类型一致,这个外键表名称为EMPLOYEE_, 表示EMPLOYEE表的主键名称。

    2.10.5、单向多值关系

    • 假设:
      • 实体A引用集合实体B
      • 实体B并不引用实体A
    • 单向关系只有一个拥有方,在上面情况下必须是实体A
    • 单向多值关系模型要么指定为单向OneToMany关系或 单向 ManyToMany 关系

    2.10.5.1 单向OneToMany关系

    • 以下映射默认设置适用:

      • 实体A映射表名A
      • 实体B映射表名B
      • join表时候名称为A_B(拥有关系者的名称写在前面)。join表有两个外键列,一个外键列引用表A并且与表A的主键类型一致。外键列名称由以下内容组成:实体A名称;"_";表A的主键名称,另一个外键引用表B并且表B的主键类型一致,外键列名称由以下内容组成:实体B名称;"_";表B的主键名称
    • 例子

      • @Entity
        public class Employee{
          private Collection<AnnualReview> annualReviews;
          
          @OneToMany
          public Collection<AnnualReview> getAnnualReviews(){
            return annualReviews;
          }
          
          public void setAnnualReviews(Collection<AnnualReview> annualReviews){
            this.annualReviews = annualReviews;
          }
          ...
        }
        
        @Entity
        public class AnnualReview{
          ...
        }
        
      • 在这个实例中:

        • Employee实体引用AnnualReview实体的集合
        • AnnualReview实体不引用Employee实体
        • Employee是关系拥有者
      • 以下映射默认设置适用:

        • Employee实体映射表名EMPLOYEE
        • AnnualReview实体映射表名ANNUALREVIEW
        • join表名名称为EMPLOYEE_ANNUALREVIEW(关系拥有者的名称写前面),join表有两个外键列,一个外键列名引用EMPLOYEE且与EMPLOYEE主键类型一致,外键列名为EMPLOYEE_, EMPLOYEE_ 表示EMPLOYEE主键名称,另一个外键引用。 另一个外键列引用ANNUALREVIEW且与ANNUALREVIEW主键类型一致,外键列名为ANNUALREVIEW_, ANNUALREVIEW_ 表示ANNUALREVIEW主键名称. 在引用表ANNUALREVIEW的外键上存在唯一的键约束。

    2.10.5.2、 单向 ManyToMany 关系

    • 以下映射默认设置适用:

      • 实体A映射表名A
      • 实体B映射表名B
      • join表名名称为A_B(拥有者名称写前面), join表有两个外键列, 一个外键列引用A表且表A的主键类型一致。外键名称由以下内容组成:实体A名称;"_";A的主键名称, 另一个外键引用表B且与表B主键类型一致。外键名称由以下内容组成:实体A名称;"_";B的主键名称
    • 例子

      • @Entity
        public class Employee{
          private Collection<Patent> patents;
          
          @ManyToMany
          public Collection<Patent> getPatents(){
            return patents;
          }
          
          public void setPatents(Collection<Patent> patents){
            this.patents = patents;
          }
          ...
        }
        
        @Entity
        public class Patent{
          ...
        }
        
      • 在这个例子中:

        • Employee实体引用Patent实体的集合对象
        • Patent没有引用Employee实体
        • Employee实体是关系拥有者
      • 以下映射默认设置适用:

        • Employee实体映射表名为EMPLOYEE
        • Patent映射表名称为PATENT
        • join表名称为EMPLOYEE_PATENT( 拥有者关系名称写在前面),join表有两个外键列,一个外键列引用EMPLOYEE表且与EMPLOYEE主键类型一致。这个外键名称为EMPLOYEE_ , 表示EMPLOYEE表的主键, 其他外键列引用PATENT表且与PATENT主键类型一致。这个外键列名称为PATENTS_ , 表示PATENT的主键名称。

    2.11 、Inheritance(继承)

    • 实体可能继承其他实体类,实体是支持继承的,多态关联和多态查询
    • 抽象类和普通类都可以作为实体,它们可以用@Entity注解标记映射成实体和并做为实体查询
    • 实体类可以扩展非实体类,同样非实体类也可以扩展实体类。
    • 在以下各节中将进一步描述这些概念

    2.11.1、抽象实体类

    • 一个抽象类可以做为实体,抽象实体类仅不同于普通实体类它不会直接被实例化, 一个抽象时态可以映射为实体和作为查询的目标(它将操作和/或检索其具体子类的实例)

    • 抽象实体类使用Entity注解进行标记,或在XML描述符中表示为实体。

    • 如下例子展示在实体继承情况下抽象实体的使用

    • 例子: 抽象类作为实体

      • @Entity
        @Table(name="EMP")
        @Inheritance(strategy=JOINED)
        public abstract class Employee{
          
          @Id protected Integer empId;
          @Version protected Integer version;
          @ManyToOne protected Address address;
          ...
        }
        
        
        
        @Entity
        @Table(name="FT_EMP")
        @DiscriminatorValue("FT")
        @PrimaryKeyJoinColumn(name="FT_EMPID")
        public class FullTimeEmployee extends Employee{
          // 继承 empId 但是映射本类的FT_EMP.FT_EMPID
          // 继承 version ,映射 EMP.VERSION
          // 继承 address 映射 EMP.ADDRESS 外键
          // 默认 FT_EMP.SALARY
          protected Integer salary;
          ...
        }
        
        
        
        @Entity
        @Table(name="PT_EMP")
        @DiscriminatorValue("PT")
        // PK列(主键)是PT_EMP.EMPID  由于PrimaryKeyJoinColumn默认值
        public class PartTimeEmployee extends Employee{
          protected Float hourlyWage;
          ...
        }
        

    2.11.2、映射超类

    • 一个实体类可能继承超类并且提供实体持久状态和映射信息, 但是它自己本身不是实体, 通常,映射超类的目标是被定义状态并且有映射信息,它一般关联多个实体。

    • 映射超类不像实体类,它不具有可查询性且禁止把它作为参数传递给EntityManger 和Query而进行操作。映射超类定义持久关系必须单向的。

    • 抽象类和普通类都可能被指定为映射超类, 可以通过MappedSuperclass注解(或在XML描述符元素mapped_superclass)标记为映射超类

    • 指定为映射超类的类没有为其定义单独的表。其映射信息将应用于从其继承的实体。

    • 可以以与实体相同的方式映射指定为映射超类的类,除了映射将仅应用于其子类外, 因为映射超类本身不存在任何表。当应用到超类上,这个继承映射将会应用到超类上下文表中。可以在超类中使用AttributeOverriede和AssociationOverride (或与之对应XML元素)进行映射信息的重写。

    • 所有其他实体映射默认应用等同于一个类设计为作为映射的超类

    • 下面例子阐述定义一个普通类作为映射超类

    • 例子: 普通类作为映射超类

      • @MappedSuperclass
        public class Employee{
          @Id protected Integer empId;
          @Version protected Integer version;
          @ManyToOne @JoinColumn(name="ADDR")
          protected Address address;
          public Integer getEmpId() { ... }
        	public void setEmpId(Integer id) { ... } 
          public Address getAddress() { ... }
        	public void setAddress(Address addr) { ... }
        }
        //定义表名为FTEMPLOYEE
        @Entity
        public class FTEmployee extends Employee{
          // 继承 empId 映射 FTEMPLOYEE.EMPID
          // 继承 version 映射 FTEMPLOYEE.VERSION
          // 继承 address 映射 FTEMPLOYEE.ADDR 外键
          // 默认是 FTEMPLOYEE.SALARY
          protected Integer salary;
          
          public FTEmployee(){}
          public Integer getSalary(){...}
          public void setSalary(Integer salary){...}
        }
        
        @Entity
        @Table(name="PT_EMP")
        //重写映射关系
        @AssociationOverride(name="address", joincolumns=@JoinColumn(name="ADDR_ID"))
        public class PartTimeEmployee extends Employee{
          // 继承 empId 映射 PT_EMP.EMPID
          // 继承 version 映射 PT_EMP.VERSION
          // 重写 address 映射 PT_EMP.ADDR_ID 外键
          @Column(name="WAGE")
          protected Float hourlyWage;
          public PartTimeEmployee(){}
          
          public Float getHourlyWage(){...}
          public void setHourlyWage(Float wage){...}
        }
        

    2.11.3、实体继承层次结构中的非实体类

    • 实体类可以有非实体超类,它可以普通类或抽象类

    • 非实体超类仅用于行为的继承,非实体超类的状态不是持久性的,继承非实体超类的实体任何状态继承都是非持久性。非持久状态是不能够被实体管理器进行管理,任何在超类上注解都会被忽略。

    • 非实体类不能作为参数调用EntityManger或Query接口(也包含非实体继承实体的类)且无法承受任何映射信息

    • 下面例子阐述使用非实体类作为实体的超类

    • 例子:非实体 超类

      • public class Cart {
          protected Integer operationCount; // transient state
          public Cart() {operationCount=0;}
          public Integer getOperationCount(){return operationCount;}
          public void incrementOperationCount(){operationCount++;}
        }
        
        
        @Entity
        public class ShoppingCart extends Cart{
          Collection<Item> items = new Vector<Item>();
          public ShoppingCart(){super();}
          ...
          @OneToMany
           public Collection<Item> getItems() {return items;}
          public void addItem(Item item){
            items.add(item);
            incrementOperationCount();
          }
        }
        

    2.12、继承映射策略

    • 类层次结构的映射是通过元数据指定的。
    • 有三种基本策略应用于 映射一个类或类层次结构映射数据库
      • 每个类层次都是单表
      • join子类策略,其中子类特有的字段被映射到一个单独的表,而不是父类共有的字段,然后执行join以实例化该子类。
      • 每个普通实体类映射一张表
    • 为了支持每个类层次映射单表的策略和join子类策略,需要实现的方式:
      • 在此版本中,对每个具体类继承映射策略的表的支持是可选的。使用此映射策略的应用程序将不可移植。
      • 本规范不要求在单个实体继承层次结构内支持继承策略的组合。

    2.12.1、每个继承层次对应单表

    • 在这个策略中,层次结构中所有类都映射一个单表,该表具有用作"区分符列"的列,即其值标识该行表示的实例所属的特定子类的列。
    • 此映射策略为实体之间的多态关系以及跨类层次结构的查询提供了良好的支持。
    • 但是,它有一个缺点,那就是要求与特定于子类的状态相对应的列可以为空。

    2.12.2、Join子类策略

    • 在join子类策略中,单表表示类层次结构的root类,每个子类都可以通过分离表表示且包含指定子类的这些字段(不是继承与超类) 也就这些列表示他们主键的列,子类表的主键列名称用作超类表的主键的外键。
    • 这个策略对于实体间多态关系提供支持。
    • 但它有一个缺点是需要执行一个或多个join操作以实例化子类的实例。在较深的类层次结构中,这可能导致无法接受的性能。 遍历类层次结构的查询同样需要join。

    2.12.3、每个具体类表策略

    • 在这个映射策略中,每个类都映射一个单独表,这个类所有属性,包含继承属性都会映射到该表列
    • 这个策略有以下缺点:
      • 对多态关系支持很弱
      • 它通常要求针对打算在类层次结构范围内进行的查询发出SQL UNION查询(或每个子类单独的SQL查询)

    2.13、数据库对象命名

    • 许多注解和注解元素包含数据库对象的名称或为了数据对象设置默认名称。

    • 关于引用数据库对象的名称解释,本规范要求以下内容。这些名称包括表名称,列名称和其他数据库元素,这些名称也包含来自默认设置的名称(例如,表名默认来自实体名称或一个列名默认来自于字段或属性名称)

    • 缺省情况下,必须将数据库对象的名称视为无界标识符,并按原样传递给数据库。

    • 举个例子,假设英语语言环境,则必须将以下内容作为无限制的标识符传递给数据库,以便对于所有符合SQL标准对“常规标识符"的要求(无限制)的数据库,它们都将被视为等效。标识符)和 “定界标识符”[2]:

      • @Table(name="Customer") 
        @Table(name="customer") 
        @Table(name="cUsTomer")
        
    • 同样,以下内容必须被视为等同:

      • @JoinColumn(name="CUSTOMER") @ManyToOne Customer customer;
        @JoinColumn(name="customer") @ManyToOne Customer customer;
        @ManyToOne Customer customer;
        
    • 要指定分隔标识符,必须使用以下方法之一:

      • 通过在对象/关系xml映射文件的persistence-unit-defaults元素内指定 元素,可以将用于持久性单元的所有数据库标识符指定为带分隔符的标识符,如果指定了元素,则不能覆盖它。
      • 可以按名称指定将数据库对象的名称解释为带分隔符的标识符,如下所示:
        • 使用注解,通过将名称用双引号引起来将名称指定定界标识符,从而对内部引号进行转义,例如@Table(name="\“customer\”")
        • 使用XML时,使用双引号将名称指定为带分隔的标识符,例如, <table name="&quot;customer&quot"
    • 以下注解包含其值与数据库标识符的名称相对应的元素,并且上述规则适用于这些元素,包括他们的使用嵌套在其他注解的使用范围内时:

      • EntityResult(discriminatorColumn 元素)
      • FieldResult(column 元素)
      • ColumnResult(name 元素)
      • CollectionTable(name,catalog,schema 元素)
      • Column(name, columnDefinition,table 元素)
      • DiscriminatorColumn(name, columnDefinition 元素)
      • ForeignKey(name,foreignKeyDefinition 元素)
      • Index(name, columnList 元素)
      • JoinColumn(name,referencedColumnName, columnDefinition, table 元素)
      • JoinTable(name,catalog, schema 元素)
      • MapKeyColumn(name, columnDefinition,table 元素)
      • MapKeyJoinColumn(name, referencedColumnName, columnDefinition, table 元素)
      • NamedStoredProcedureQuery(procedureName 元素)
      • OrderColumn(name, columnDefinition 元素)
      • PrimaryKeyJoinColumn(name, referencedColumnName, columnDefinition 元素)
      • SecondaryTable(name, catalog, schema 元素)
      • SequenceGenerator(sequenceName, catalog, schema 元素)
      • StoredProcedureParameter(name 元素)
      • Table(name,catalog,schema 元素)
      • TableGenerator(table, catalog, schema, pkColumnName, valueColumnName 元素)
      • UniqueConstraint(name, columnNames元素)
    • 以下XML元素和类型包含其值对应于的元素或属性上面规则适用的数据库标识符的名称:

      • entity-mappings(schema, catalog 元素)
      • persistence-unit-defaults(schema, catalog 元素)
      • collection-table(name,catalog,schema 属性)
      • column(name,table,column-definition 属性)
      • column-result(name属性)
      • discriminator-column(name, column-definition 属性)
      • entity-result(discriminator-column 属性)
      • field-result(column 属性)
      • foreign-key(name, foreign-key-definition 属性)
      • index(name 属性, column-list 元素)
      • join-column(name, referenced-column-name, column-definition, table 属性)
      • join-table(name, catalog, schema 属性)
      • map-key-column(name,column-definition,table属性)
      • map-key-join-column(name, referenced-column-name, column-definition,table 属性)
      • named-stored-procedure-query(procedure-name 属性)
      • order-column(name, column-definition 属性)
      • primary-key-join-column(name, referenced-column-name, column-definition 属性)
      • secondary-table(name, catalog, schema 属性)
      • sequence-generator(sequence-name, catalog, schema 属性)
      • stored-procedure-parameter(name 属性)
      • table(name, catalog, schema属性)
      • table-generator(table, catalog, schema, pk-column-name, value-column-name 属性)
      • unique-constraint(name属性, column-name 元素)
    展开全文
  • 如A表的 PA, PB, PC是复合主键, 则PA不能作为B表的外键 只能PA,PB,PC组成B表的复合外键
    如A表的 PA, PB, PC是复合主键, 则PA不能作为B表的外键
    只能PA,PB,PC组成B表的复合外键
    展开全文
  • 实体-联系(E-R)数据模型基于对现实世界的这样一种认识:世界由一组称为实体的基本对象及这些对象间的联系组成。E-R数据模型所采用的三个主要概念是:实体集、联系集和属性 实体实体是现实世界中可区别于其他...
  • 数据库实体联系模型与关系模型

    千次阅读 2020-03-02 19:11:33
    当关系中存在多个关键字时,称它们为候选关键字,指定其中一个为主关键字,简称主键。 设计二维表时,关系应满足如下性质。 (1)表中每一列的取值范围都是相同的,也就是数据类型相同。 (2)不同列的取值...
  • 在ER模型中,弱实体用双矩形框表示,联系则用双菱形(该弱实体依赖于实体而存在,则与实体的之间是1:*联系) 2.属性 在ER模型中,单值属性用椭圆形表示 在ER模型中,多值属性用椭圆形表示(会产生大量的数据冗余...
  • 实体集(Entity Sets) ...举行代表实体集,上方为名字,下方是属性,主键用下划线标出 菱形代表关系集 线段连接实体集和关系集 虚线连接一个关系集和它的描述属性 双线表示实体集对于关系集的全参与 双菱形表示
  • CODE-FIRST 实体编写

    2015-07-03 00:32:47
    EF实体创建规范 1 说明 为了在界面操作和数据操作方便,整理出EF实体创建规范。后续持续进行文件更新。 (以下特性生成使用MVC4+EF6.1.3) ...2.2 外键,注意外键和外键表的主键类型要一致。   publi
  • MySql (四) ER图与实体关系映射

    千次阅读 2017-10-07 05:49:09
    实体关系映射什么是数据库的设计?数据库设计(Database Design)是指对于一个给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,使之能够有效地存储数据,满足各种用户的应用需求(信息要求和处理要求...
  • Entity-Relationship Modeling – 实体联系建模 1 .实体类型 1.1 实体类型 定义:被企事业单位认可的、能够独立存在的一组具有相同属性的对象 ER模型的基本概念是实体类型,实体类型代表现实世界中具有相同属性的一...
  • 文章目录一,实体集1,实体集表示为表2...E-R 图1,E-R 图1.2 角色2,具有三元联系的E-R图3,二元与非二元联系4,弱实体集七,扩展的E-R特性1,特化与概化2,对特化/概化的设计约束3,聚集4,E-R图表示法中使用的符...
  • 管理软件的实体设计

    2014-02-23 13:19:00
    1 管理软件的实体设计 本文介绍管理软件研发进行实体设计时候一般考虑的问题,然后介绍笔者的一个作品中的实体设计。 1.1 实体的主要职责 序号 职责 说明 附加说明 1 ...
  • 今天与同事一起讨论了2种数据实体层的设计方案哪个比较好的问题,只有讨论,虽然心里... 方案2是类型设计,实体继承自DataTable;两种方案都是一个表/视图对应一个数据实体。 相应的数据访问层都采用Provider模...
  • 数据库 - 建模:实体关系图(ERD)

    万次阅读 2018-10-27 10:32:34
    实体关系模型,也称为实体关系(ER)图,是实体(将成为您的表)及其相互关系的图形表示。 数据库建模是创建数据模型的过程。 实体 一个简单的矩形块代表一个表。 关系 它使用钻石形状勾勒出来。 关系...
  • 实体集:相似的实体 实体通过属性来描述。 对于每个与实体集相关的属性,必须确定该属性的值域。 对于每个实体集,我们都选择一个key,key就是一组最小的属性集合。它们的值能唯一确定实体中的每个实体。有可能...
  • 如果由两个列共同组成主键,而且一个子表将主键作为可为空值的外键来继承,就可能得到错误的数据。可在一个外键列中插入有效的值,但在另一个外键列中插入空值。然后,可添加一个数据表检查约束,在可为空的外键中...
  • 概念设计(Conceptual Design) —— 设计实体关系模型 (ER Model) 逻辑设计(Logical Design)—— 实现从 ER 模型到关系模式(Relation Schemas)的转换。 物理设计(Physical Design) 本文主...
  • 实体关系模型 基础的 ER 建模概念 实体:某类事物,区别于其他事物。实体具有属性(attribute)。一个人可以是一个实体,一只猫也可以是一个实体,人之所以区别于猫,是因为人具有很多猫不具有的属性 实体集:一类...
  • 一、什么是实体  由标识来区分的对象称为实体。  实体的定义隐藏了几个信息: 两个实体对象,只要它们的标识属性值相等,哪怕标识属性以外的所有属性值都不相等,这两个对象也认为是同一个实体,这意味着两个...
  • E-R模型和关系模型

    千次阅读 2018-10-10 21:37:14
    其定义为一个实体对于另一个实体(一般为强实体,也可以是依赖于其他强实体的弱实体)具有很强的依赖联系,而且该实体主键的一部分或全部从其强实体(或者对应的弱实体依赖的强实体)中获得,则称该实体为弱实...
  • 上一篇,我介绍了自己在DDD分层架构方面的一些感想,本文开始介绍领域层的实体,代码主要参考自《领域驱动设计C#2008实现》,另外参考了网上找到的一些示例代码。 什么是实体  由标识来区分的对象称为实体。  ...
  • Lily.Core组件是在Vs2003+Sqlserver2000下的开发和进行测试的。Lily.Core组件是一个轻量级的和数据库打交道的并不是一个真正意义...Lily.Core对于事务的控制很,使用了Ado.Net中事务对象的传递来完成对事务的控制...
  • 软考二进宫-增强的ER模型

    千次阅读 热门讨论 2016-04-30 08:43:49
    实体A对于实体B具有很强的依赖关系,而且A主键的一部分或全部从B获得,则称A为弱实体,B为强实体 ER模型中, (1)弱实体用双线矩形框表示, (2)与弱实体的联系,用双线菱形框表示, (3)弱实体与强实体的联系只能...
  • 1.几个基本概念 实体-联系(E-R)模型是基于如下的一种认识:世界由一组实体实体之间的相互联系组成。E-R模型是一种语义模型, 前面也提到过,这种模型经常作为关系数据库模型的基础。 很多数据库设计工具也都使用了...
  • 作业是做一个学生选课系统,建表的时候就报出 消息 1776,级别 16,状态 ...其中,开课信息表属于弱实体集,通过联系集开设课程依赖于强实体集课程信息表。开课信息表的主码由开课编号、学期、学年以及 课程编号组成。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,037
精华内容 2,414
关键字:

弱实体的主键