【问题标题】:Hibernate - OneToMany Bidirectional Insert resulting in nullHibernate - OneToMany 双向插入导致 null
【发布时间】:2016-05-16 04:14:12
【问题描述】:

所以,我正在使用 Hibernate 5 和 SpringMVC 4 制作这个 webapp。 由于某种原因,我不能插入具有 OneToMany 关系的实体。 在我首先解释任何事情之前,我想说我尝试了这里和其他论坛发布的许多解决方案,但都没有为我工作......我不知道我在尝试解决问题时是否做错了。

这是我的数据库:

现在,我最近添加了电话桌。在此之前,我可以添加一个配置文件对象,它将在同一事务中级联地址和用户实体的插入。现在,在代码中添加电话实体后,持久化操作一直在抛出我

列“ProfileId”不能为空

所有类都有各自的 Setter 和 Getter...但为了保持代码简短,我删除了它们。

@Entity
@Table(name = "profile")
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @NotEmpty
    @Size(max = 100)
    @Column(name = "FirstName", nullable = false, unique = false, length = 100)
    private String firstName;

    @NotEmpty
    @Size(max = 100)
    @Column(name = "LastName", nullable = false, unique = false, length = 100)
    private String lastName;

    @NotNull
    @DateTimeFormat(pattern = "MM/dd/yyyy")
    @Column(name = "BirthDate", nullable = false, unique = false)
    private Timestamp birthDate;

    @Valid
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "UserId")
    private User user;

    @Valid
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "AddressId")
    private Address address;

    @Valid
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "profile", cascade = CascadeType.ALL)
    private List<Phone> phones;
}

_

@Entity
@Table(name = "Phone")
public class Phone {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @NotEmpty
    @Size(max = 50)
    @Column(name = "PhoneNumber", nullable = false, unique = false, length = 50)
    private String phoneNumber;

    @Valid
    @ManyToOne(cascade = CascadeType.ALL, optional = false)
    @JoinColumn(name = "ProfileId", nullable = false)
    private Profile profile;
}

_

@Entity
@Table(name = "\"User\"", uniqueConstraints = { @UniqueConstraint(columnNames = "Username") })
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id", unique = true, nullable = false)
    private long id;

    @Column(name = "Username", nullable = false, unique = true, length = 80)
    private String username;

    @Column(name = "Password", nullable = false, length = 128)
    private String password;

    @Valid
    @OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
    private Profile profile;
}

_

@Entity
@Table(name = "Address")
public class Address {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "FullAddress", nullable = false, unique = false, length = 100)
    private String fullAddress;

    @Column(name = "City", nullable = false, unique = false, length = 100)
    private String city;

    @Column(name = "PostalCode", nullable = false, unique = false, length = 100)
    private String postalCode;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "address", cascade = CascadeType.ALL)
    private Profile profile;
}

在我为类似案例找到的解决方案之间是:

  • 更改 Phone 表的 ProfileId 列以使其允许空值,但保留 JoinColumn 注释上的 nullable = false。这样做的结果是它实际上插入了所有实体,但 ProfileId 也被保存为 null。
  • 更改了级联类型...仍然是同样的错误。
  • 有人说 EntityManager 上下文发生冲突。这不是我的情况。
  • 将可以为空的 JoinColumn 注释属性设置为 false。已经这样做了,仍在代码中,也无法正常工作。
  • 在关系的两边设置级联类型。也做了,也还在代码上,不工作。
  • 将可选的 ManyToOne 关系属性设置为 false。也不行。

和我一样新.. 我的理解是 ProfileId 正在接收 null,因为由于某种原因,在插入 Profile 表之后,生成的 id 尚未在配置文件对象上设置,这导致手机插入失败。但我不知道如何解决。

如果您需要知道我是如何持久化对象的...

sessionFactory.getCurrentSession().persist(profile);

而且 sessionFactory 是自动装配的。 配置文件对象具有以下内容:

{"phones":[{"phoneNumber":"123456789"}],"user":{"username":"Nameeeeee@alksjd.com","password":"123123123"},"firstName":"Nameeeeee","lastName":"Nameeeeee","birthDate":"02/05/2016", "address":{"fullAddress":"laksjdlkas","city":"alksjdlkasjd","postalCode":"101010"}}

最后是完整的错误:

Hibernate: 
    insert 
    into
        Address
        (FullAddress, City, PostalCode) 
    values
        (?, ?, ?)
Hibernate: 
    select
        last_insert_id()
Hibernate: 
    insert 
    into
        `User` (
            Password, Username
        ) 
    values
        (?, ?)
Hibernate: 
    select
        last_insert_id()
Hibernate: 
    insert 
    into
        Profile
        (AddressId, BirthDate, FirstName, LastName, UserId) 
    values
        (?, ?, ?, ?, ?)
Hibernate: 
    select
        last_insert_id()
Hibernate: 
    insert 
    into
        Phone
        (PhoneNumber, ProfileId) 
    values
        (?, ?)
WARN  SqlExceptionHelper::logExceptions:127 - SQL Error: 1048, SQLState: 23000
ERROR SqlExceptionHelper::logExceptions:129 - Column 'ProfileId' cannot be null

添加请求的代码。

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = { "com.configuration" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {

    final static Logger logger = Logger.getLogger(HibernateConfiguration.class);
    @Autowired
    private Environment environment;

    @Bean
    public LocalSessionFactoryBean sessionFactoryBean() {
        logger.info("Creating LocalSessionFactoryBean...");
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource());
        sessionFactoryBean.setPackagesToScan(new String[] { "com.model" });
        sessionFactoryBean.setHibernateProperties(hibernateProperties());
        return sessionFactoryBean;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory);
        return transactionManager;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.temp.use_jdbc_metadata_defaults",
                environment.getRequiredProperty("hibernate.temp.use_jdbc_metadata_defaults"));
    }

【问题讨论】:

    标签: java mysql hibernate


    【解决方案1】:

    你应该在代码中的某个地方这样做

    Phone phone = new Phone();
    //... set phone vars
    phone.setProfile(profile);
    
    sessionFactory.getCurrentSession().persist(profile);
    

    【讨论】:

    • 感谢您的回答。但我仍然得到完全相同的错误。
    • 我有一个疑问..你的意思是 sessionFactory.getCurrentSession().persist(phone); 吗?
    • 我的意思是 profile 。由于您将电话附加到配置文件中,因此它们应该与它一起保留。您会在创建 Profile 和 Phone 对象并设置引用的位置发布代码吗?
    • 好的,它起作用了..现在我不明白为什么! Profile 对象来自 Json 中的前端。使用上面发布的相同数据,其中已经包括电话。为什么我必须重新设置它?非常感谢您的帮助,对不起,我让您浪费了您的时间。
    • 好吧,没关系!我看到了区别!非常感谢您的宝贵时间!
    猜你喜欢
    • 2019-05-22
    • 2013-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 1970-01-01
    • 2013-03-15
    相关资源
    最近更新 更多