如何使用 Hibernate 注释来持久化双向一对一关系实体?

How to persist Bidirectional one to one relational entities using Hibernate annotations?

我有三个表 Company、Contact 和 Address,在(公司和联系人)和(公司和地址)之间具有双向一对一关系。该关系是通过关系所有者(公司)中的外键。

Company.java

@Entity
@Table(name="company")
public class Company implements Serializable {

    private static final long serialVersionUID = 1L;
    private int companyId;
    private String companyName;
    private String paymentTerms;
    private Address address;
    private Contact contact;

    public Company(){ }

    public Company(String companyName,String paymentTerms){
        this.companyName = companyName;
        this.paymentTerms = paymentTerms;
    }

    @Id
    public int getCompanyId() {
        return companyId;
    }
    public void setCompanyId(int companyId) {
        this.companyId = companyId;
    }

    public String getCompanyName() {
        return companyName;
    }
    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public String getPaymentTerms() {
        return paymentTerms;
    }
    public void setPaymentTerms(String paymentTerms) {
        this.paymentTerms = paymentTerms;
    }
    @OneToOne(cascade=CascadeType.ALL,fetch = FetchType.LAZY)
    @JoinColumn(name="address_addressId",insertable=true,updatable=true,nullable=true,unique=true)
    public Address getAddress() {
        return address;
    }   
    public void setAddress(Address address) {
        this.address = address;
    }
    @OneToOne(cascade=CascadeType.ALL,fetch = FetchType.LAZY)
    @JoinColumn(name="contact_contactId",insertable=true,updatable=true,nullable=true,unique=true)
    public Contact getContact() {
        return contact;
    }

    public void setContact(Contact contact) {
        this.contact = contact;
    }

    @Override
    public String toString() {
        return "Company [companyId=" + companyId + ", companyName="
                + companyName + ", paymentTerms=" + paymentTerms + ", address="
                + address + ", contact=" + contact + "]";
    }
}

Contact.java

   @Entity
public class Contact {

    private int contactId;
    private String contactPerson;
    private String email;
    private String mobileNumber;
    private String landlineNumber;
    private Company company;

    public Contact(){}

    @Id 
    public int getContactId() {
        return contactId;
    }

    public void setContactId(int contactId) {
        this.contactId = contactId;
    }   
    public String getContactPerson() {
        return contactPerson;
    }
    public void setContactPerson(String contactPerson) {
        this.contactPerson = contactPerson;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getMobileNumber() {
        return mobileNumber;
    }
    public void setMobileNumber(String mobileNumber) {
        this.mobileNumber = mobileNumber;
    }
    public String getLandlineNumber() {
        return landlineNumber;
    }
    public void setLandlineNumber(String landlineNumber) {
        this.landlineNumber = landlineNumber;
    }
    @OneToOne(mappedBy="contact")
    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}

Address.java

   @Entity
public class Address {

    private int addressId;
    private String addressLine1;
    private String addressLine2;
    private String city;
    private String state;
    private String postalCode;
    private Company company;

    public Address(){}

    public Address(String addressLine1,String addressLine2,String city,String state,String postalCode){
        this.addressLine1 = addressLine1;
        this.addressLine2 = addressLine2;
        this.city = city;
        this.state = state;
        this.postalCode = postalCode;
    }

    @Id
    public int getAddressId() {
        return addressId;
    }
    public void setAddressId(int addressId) {
        this.addressId = addressId;
    }   
    public String getAddressLine1() {
        return addressLine1;
    }
    public void setAddressLine1(String addressLine1) {
        this.addressLine1 = addressLine1;
    }
    public String getAddressLine2() {
        return addressLine2;
    }
    public void setAddressLine2(String addressLine2) {
        this.addressLine2 = addressLine2;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    public String getPostalCode() {
        return postalCode;
    }
    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }
    @OneToOne(mappedBy="address")
    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}

public void addCompany(Company company,Contact contact,Address address){
        try{
            emf = Persistence.createEntityManagerFactory("company");
            em = emf.createEntityManager();
            em.getTransaction().begin();

            //address.setAddressId(company.getCompanyId());
            company.setAddress(address);
            company.setContact(contact);

            //contact.setContactId(company.getCompanyId());
            em.persist(address);
            em.persist(contact);
            em.persist(company);

            em.getTransaction().commit();
            em.close();
        }catch(PersistenceException e){
            e.printStackTrace();
        }
}

我收到错误无法添加或更新子行:外键约束失败 (mydb.company, CONSTRAINT fk_company_contact FOREIGN KEY (contact_contactId ) 参考文献 contact (contactId) 删除时无操作更新时无操作)

`Apr 18, 2015 11:24:57 AM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.8.0_25\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.8.0_25\jre\bin;C:/Program Files/Java/jdk1.8.0_25/bin/../jre/bin/server;C:/Program Files/Java/jdk1.8.0_25/bin/../jre/bin;C:/Program Files/Java/jdk1.8.0_25/bin/../jre/lib/amd64;C:\WINDOWS\system32;C:\Program Files\Java\jdk1.8.0_25\bin;U:\EclipseJEE\eclipse;;.
Apr 18, 2015 11:24:57 AM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:Struts 2 Portfolio' did not find a matching property.
Apr 18, 2015 11:24:58 AM org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
Apr 18, 2015 11:24:58 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1502 ms
Apr 18, 2015 11:24:58 AM org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
Apr 18, 2015 11:24:58 AM org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.37
Apr 18, 2015 11:25:00 AM com.opensymphony.xwork2.config.providers.XmlConfigurationProvider info
INFO: Parsing configuration file [struts-default.xml]
Apr 18, 2015 11:25:00 AM com.opensymphony.xwork2.config.providers.XmlConfigurationProvider info
INFO: Unable to locate configuration files of the name struts-plugin.xml, skipping
Apr 18, 2015 11:25:00 AM com.opensymphony.xwork2.config.providers.XmlConfigurationProvider info
INFO: Parsing configuration file [struts-plugin.xml]
Apr 18, 2015 11:25:00 AM com.opensymphony.xwork2.config.providers.XmlConfigurationProvider info
INFO: Parsing configuration file [struts.xml]
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.ObjectFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.factory.ActionFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.factory.ResultFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.factory.ConverterFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.factory.InterceptorFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.factory.ValidatorFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.factory.UnknownHandlerFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.FileManagerFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.XWorkConverter)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.CollectionConverter)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.ArrayConverter)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.DateConverter)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.NumberConverter)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.impl.StringConverter)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ConversionFileProcessor)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.TypeConverterCreator)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.TypeConverterHolder)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.TextProvider)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.LocaleProvider)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.ActionProxyFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.conversion.ObjectTypeDeterminer)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (org.apache.struts2.dispatcher.mapper.ActionMapper)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (jakarta) for (org.apache.struts2.dispatcher.multipart.MultiPartRequest)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (org.apache.struts2.views.freemarker.FreemarkerManager)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (org.apache.struts2.components.UrlRenderer)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.validator.ActionValidatorManager)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.util.ValueStackFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.util.reflection.ReflectionProvider)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.util.reflection.ReflectionContextFactory)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.util.PatternMatcher)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (org.apache.struts2.dispatcher.StaticContentLoader)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.UnknownHandlerManager)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (org.apache.struts2.views.util.UrlHelper)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.util.TextParser)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (org.apache.struts2.dispatcher.DispatcherErrorHandler)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.security.ExcludedPatternsChecker)
Apr 18, 2015 11:25:00 AM org.apache.struts2.config.AbstractBeanSelectionProvider info
INFO: Choosing bean (struts) for (com.opensymphony.xwork2.security.AcceptedPatternsChecker)
Apr 18, 2015 11:25:02 AM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
Apr 18, 2015 11:25:02 AM org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
Apr 18, 2015 11:25:02 AM org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/68  config=null
Apr 18, 2015 11:25:02 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 4427 ms
Apr 18, 2015 11:25:04 AM org.apache.struts2.components.ServletUrlRenderer warn
WARNING: No configuration found for the specified action: 'Login' in namespace: '/authentication'. Form action defaulting to 'action' attribute's literal value.
Apr 18, 2015 11:25:05 AM org.apache.struts2.components.ServletUrlRenderer warn
WARNING: No configuration found for the specified action: 'Login' in namespace: '/authentication'. Form action defaulting to 'action' attribute's literal value.
Apr 18, 2015 11:25:09 AM com.opensymphony.xwork2.interceptor.ParametersInterceptor error
SEVERE: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'login' on 'class authentication.Authentication: Error setting expression 'login' with value ['Login', ]
Apr 18, 2015 11:25:10 AM org.apache.struts2.components.ServletUrlRenderer warn
WARNING: No configuration found for the specified action: 'Logout' in namespace: '/home'. Form action defaulting to 'action' attribute's literal value.
Apr 18, 2015 11:25:10 AM org.apache.struts2.components.ServletUrlRenderer warn
WARNING: No configuration found for the specified action: 'Logout' in namespace: '/home'. Form action defaulting to 'action' attribute's literal value.
Apr 18, 2015 11:25:12 AM org.apache.struts2.components.ServletUrlRenderer warn
WARNING: No configuration found for the specified action: 'add' in namespace: '/company'. Form action defaulting to 'action' attribute's literal value.
Apr 18, 2015 11:25:13 AM org.apache.struts2.components.ServletUrlRenderer warn
WARNING: No configuration found for the specified action: 'add' in namespace: '/company'. Form action defaulting to 'action' attribute's literal value.
Apr 18, 2015 11:25:28 AM org.hibernate.ejb.HibernatePersistence logDeprecation
WARN: HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
Apr 18, 2015 11:25:28 AM org.hibernate.ejb.HibernatePersistence logDeprecation
WARN: HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
Apr 18, 2015 11:25:28 AM org.hibernate.ejb.HibernatePersistence logDeprecation
WARN: HHH015016: Encountered a deprecated javax.persistence.spi.PersistenceProvider [org.hibernate.ejb.HibernatePersistence]; use [org.hibernate.jpa.HibernatePersistenceProvider] instead.
Apr 18, 2015 11:25:29 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [
    name: company
    ...]
Apr 18, 2015 11:25:31 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.3.8.Final}
Apr 18, 2015 11:25:31 AM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Apr 18, 2015 11:25:31 AM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Apr 18, 2015 11:25:33 AM org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl processProperties
WARN: HHH000059: Defining hibernate.transaction.flush_before_completion=true ignored in HEM
Apr 18, 2015 11:25:35 AM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
Apr 18, 2015 11:25:36 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH000402: Using Hibernate built-in connection pool (not for production use!)
Apr 18, 2015 11:25:36 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000401: using driver [com.mysql.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/mydb]
Apr 18, 2015 11:25:36 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000046: Connection properties: {user=root}
Apr 18, 2015 11:25:36 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000006: Autocommit mode: false
Apr 18, 2015 11:25:36 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
Apr 18, 2015 11:25:37 AM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
Apr 18, 2015 11:25:40 AM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate: 
    insert 
    into
        Address
        (addressLine1, addressLine2, city, postalCode, state, addressId) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        Contact
        (contactPerson, email, landlineNumber, mobileNumber, contactId) 
    values
        (?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        company
        (address_addressId, companyName, contact_contactId, paymentTerms, companyId) 
    values
        (?, ?, ?, ?, ?)
Apr 18, 2015 11:26:00 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1452, SQLState: 23000
Apr 18, 2015 11:26:00 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Cannot add or update a child row: a foreign key constraint fails (`mydb`.`company`, CONSTRAINT `fk_company_contact` FOREIGN KEY (`contact_contactId`) REFERENCES `contact` (`contactId`) ON DELETE NO ACTION ON UPDATE NO ACTION)
Apr 18, 2015 11:26:00 AM org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl release
INFO: HHH000010: On release of batch it still contained JDBC statements
Apr 18, 2015 11:26:00 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 1452, SQLState: 23000
Apr 18, 2015 11:26:00 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: Cannot add or update a child row: a foreign key constraint fails (`mydb`.`company`, CONSTRAINT `fk_company_contact` FOREIGN KEY (`contact_contactId`) REFERENCES `contact` (`contactId`) ON DELETE NO ACTION ON UPDATE NO ACTION)

`

  1. 由于实体具有双向关系,您必须在 addCompany 方法中引用它们。这与异常有关:

    WARN: Cannot add or update a child row: a foreign key constraint fails

  2. 您不使用自动 id 生成,因此您需要在所有实体的 addCompany 方法中明确执行此操作。您可以选择让 Hibernate 为您做这件事,方法是使用 @GeneratedValue 注释 get*Id() 方法并选择合适的 id generation strategy

  3. 级联双向关系允许您跳过非拥有方(ContactAddress)实体的显式持久化

  4. 多次创建 EntityManagerFactory 会给您的应用程序增加大量开销,应该避免。只需创建一次,让 EntityManager 个实例重用它。

  5. 您也可以考虑为 addMethod 的多次调用创建一次 EntityManager(例如,在 addMethod 的 class 中或通过注入)并仅在不再需要。


emf 的初始化移动到其他地方:

emf = Persistence.createEntityManagerFactory("company"); // 4.

addCompany 方法的更新版本:

em = emf.createEntityManager(); // 5.    
...
public void addCompany(Company company, Contact contact, Address address) {
    em.getTransaction().begin();

    company.setAddress(address);
    company.setContact(contact);

    contact.setCompany(company); // 1.
    address.setCompany(company); // 1.
    em.persist(company); // 3.

    em.getTransaction().commit();
}
...
em.close(); // 5.