【问题标题】:Spring Data Thymeleaf-cannot insert related record, foreign key nullSpring Data Thymeleaf - 无法插入相关记录,外键为空
【发布时间】:2017-07-19 03:40:09
【问题描述】:

我有 2 个具有一对多关系的实体。相关子条目插入失败,因为外键为空。 在测试中工作

看起来高低,大多数都解决了,因为提问者没有将孩子添加到父母,这不是我的情况。任何帮助表示赞赏!

错误

引起:java.sql.SQLIntegrityConstraintViolationException: ORA-01400: 无法将 NULL 插入 ("AIWA"."CAT_DT"."CAT_ID")

编辑 1:在下方添加详细的错误日志。

2017-03-01 09:45:04 调试 JpaTransactionManager:759 - 启动 事务提交 2017-03-01 09:45:04 DEBUG JpaTransactionManager:512 - 在 EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@640a6fdf] 上提交 JPA 事务 2017-03-01 09:45:04 调试 SQL:109 - 插入 进入 猫 (CATTYPE, ..., ID) 价值观 (?, ?, ?, ?, ?, ?, ?, ?, ?) 2017-03-01 09:45:04 TRACE BasicBinder:81 - 绑定参数 [1] 作为 [NUMERIC] - [200] 2017-03 -01 09:45:04 TRACE BasicBinder:69 - 将参数 [2] 绑定为 [VARCHAR] - [null] 2017-03-01 09:45:04 TRACE BasicBinder:81 - 绑定参数 [3] 作为 [VARCHAR] - [1] 2017-03-01 09:45:04 TRACE BasicBinder:69 - 绑定参数 [4] 作为 [VARCHAR] - [null] 2017-03-01 09:45:04 TRACE BasicBinder:69 - 绑定参数 [5] 作为 [VARCHAR] - [null] 2017-03-01 09:45:04 TRACE BasicBinder:69 - 绑定参数 [6] 为 [VARCHAR] - [null] 2017-03-01 09:45:04 TRACE BasicBinder:81 - 绑定 参数 [7] 作为 [NUMERIC] - [1] 2017-03-01 09:45:04 TRACE BasicBinder:69 - 绑定参数 [8] 作为 [VARCHAR] - [null] 2017-03-01 09:45:04 TRACE BasicBinder:81 - 绑定参数 [9] 为 [数字] - [182] 2017-03-01 09:45:04 调试 SQL:109 - 插入 进入 CAT_DT (CAT_ID、DESCR、LANGUAGE、NAME、SORTNAME、ID) 价值观 (?, ?, ?, ?, ?, ?) 2017-03-01 09:45:04 TRACE BasicBinder:69 - 绑定参数 [1] 作为 [NUMERIC] - [null] 2017-03-01 09:45: 04 追踪 BasicBinder:81 - 绑定参数 [2] 作为 [VARCHAR] - [a] 2017-03-01 09:45:04 TRACE BasicBinder:81 - 绑定参数 [3] 作为 [NUMERIC] - [1] 2017-03-01 09:45:04 TRACE BasicBinder:81 - 绑定参数 [4] 作为 [VARCHAR] - [a] 2017-03-01 09:45:04 TRACE BasicBinder:69 - 绑定 参数 [5] 作为 [VARCHAR] - [null] 2017-03-01 09:45:04 TRACE BasicBinder:81 - 绑定参数 [6] 作为 [NUMERIC] - [264] 2017-03-01 09:45:04 WARN SqlExceptionHelper:144 - SQL 错误:1400,SQLState: 23000 2017-03-01 09:45:04 错误 SqlExceptionHelper:146 - ORA-01400: 无法将 NULL 插入 ("CAT_DT"."CAT_ID")

2017-03-01 09:45:04 信息 AbstractBatchImpl:208 - HHH000010:开启 批次发布仍包含 JDBC 语句 2017-03-01 09:45:04 调试 JpaTransactionManager:898 - 启动事务 提交异常后回滚

实体

public class Cat{
    private List<CatDt> catDts = new ArrayList<CatDt>();

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "cat", cascade=CascadeType.ALL)
    public List<CatDt> getCatDts() {
        if(this.catDts==null){
            this.catDts = new ArrayList<CatDt>();
        }
        return this.catDts;
    }

    public void setCatDts(List<CatDt> catDts) {
        this.catDts = catDts;
    }
}

public class CatDt{
    private Cat cat;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @JoinColumn(name = "CAT_ID", nullable = false)
    public Cat getCat() {
        return this.cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }
}

百里香叶形式

<ul th:each="item, stat: *{catDts}">
    <li>
        <span th:text="#{front.cat.CatDt.no.label}">No</span>
        <label th:text="${stat.count}">1</label>
    </li>
    <li>
        <span th:text="#{front.cat.CatDt.name.label}">Name</span>
        <input type="text" th:field="*{catDts[__${stat.index}__].name}" th:id="${'name-'+stat.index}">
    </li>
    <li>
        <span th:text="#{front.cat.CatDt.descr.label}">Description</span>
        <input type="text" th:field="*{catDts[__${stat.index}__].descr}" th:id="${'descr-'+stat.index}">
    </li>
    <li>
        <span th:text="#{front.cat.CatDt.lang.label}">Language</span>
        <input type="text" th:field="*{catDts[__${stat.index}__].language}" th:id="${'language-'+stat.index}">
    </li>       
</ul>

生成的 HTML 表单

<form action="/aiwaweb/cat/create" method="post">
    <!-- Main info -->
    <ul>
        <li>
            <span>Code</span>
            <input id="code" name="code" value="" type="text">          
        </li>
        <li>
            <span>Type</span>
            <select id="catType" name="catType">
                <option...>...</option>
            </select>
        </li>
        <li>
            <span>Status</span>
            <select id="status" name="status">
                <option value="0">INACTIVE</option>
                <option value="1">ACTIVE</option>
            </select>
        </li>           
    </ul>

    <!-- Details -->    
    <ul>
        <li>
            <span>No.</span>
            <label>1</label>
        </li>
        <li>
            <span>Name</span>
            <input id="name-0" name="catDts[0].name" value="" type="text">
        </li>
        <li>
            <span>Description</span>
            <input id="descr-0" name="catDts[0].descr" value="" type="text">
        </li>
        <li>
            <span>Language</span>
            <input id="language-0" name="catDts[0].language" value="" type="text">
        </li>
    </ul>
</form>

Edit 2 更新了控制器 create() 以将 Cat 添加到 CatDt(之前它只是将 catDt 添加到 Cat);希望这种 2 向关系链接能够解决,但没有。

控制器

@GetMapping({"/create"})
public String create(ModelMap model){
    Cat cat = new Cat();
    List<CatDt> catDts = new ArrayList<CatDt>();
    CatDt catDt = new CatDt();
    catDt.setCat(cat); //this is the extra line added
    catDts.add(catDt);
    cat.setCatDts(catDts);
    model.addAttribute("cat", cat);
    return "cat/create";
}

@PostMapping(value="/create", params={"save"})
public String save(final Cat cat
        , final BindingResult bindingResult, final ModelMap model){
    if(bindingResult.hasErrors()){
        return "cat/create";
    }
    Cat updatedCat = catService.save(cat);
    model.clear();
    return "redirect:/cat/create";
}

到目前为止我做了什么

  1. 当我在控制器 save() 上调试时,Cat 在 List 中有子 CatDt,但 CatDt 的 cat 属性为 null;但仔细想想,也许它应该为 null,因为 Cat 还没有保存,所以还没有 Id。

单元测试

@Test
public void testCatSave(){
    Cat cat = new Cat();
    cat.setCode("11111");
    ...     
    //add cat details
    List<CatDt> catDts = new ArrayList<CatDt>();        
    CatDt catDt = new CatDt();
    catDt.setCat(cat);
    catDt.setName("Test");
    ...
    catDts.add(catDt);
    cat.setCatDts(catDts);          
    Cat catUpdated = catService.save(cat);
}

持久性配置

public class PersistenceConfig {
    @Autowired
    private Environment env;

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory()
    {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(dataSource());
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setJpaProperties(hibernateProperties());
        factory.setPackagesToScan("ae.tbits.atn.aiwacore.common.model");
        return factory;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
    {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(emf);
        return txManager;
    }

    @Bean
    public HibernateExceptionTranslator hibernateExceptionTranslator(){
        return new HibernateExceptionTranslator();
    }

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

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", env.getRequiredProperty("hibernate.format_sql"));
env.getRequiredProperty("hibernate.type"));
        return properties;        
    }     
}

跟随这个到 T,但不保存子记录 http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#the-controller

【问题讨论】:

  • 添加了编辑 1,显示了更多的日志。可以看到父母和孩子的两组插入语句。不知何故 child 没有得到新插入的 parent id 。我是否需要手动执行任何操作,例如 commitflush ?如果是,因为我尝试过并且我的 mvc 代码抛出错误( no transaction in progress )。我的服务只是调用 repo 的 Cat.save();测试运行良好。还是需要对实体或配置进行一些更改?

标签: java hibernate spring-data-jpa thymeleaf


【解决方案1】:

好的,所以我终于能够解决了。结果以某种方式没有将子 catDts 添加到 cat 对象中。

在控制器 save() 中,我手动重新分配并保存。

public String save(final Cat cat
        , final BindingResult bindingResult, final ModelMap model){
    if(bindingResult.hasErrors()){
        logger.info("Binding result error in create(save)");
        return "cat/create";
    }
    //manually reassign - start
    List<CatDt> catDts = cat.getCatDts();
    for (CatDt catDt : catDts) {
        catDt.setCat(cat);
    }
    cat.setCatDts(catDts);
    //manually reassign - end

    Cat updatedCat = catService.save(cat); //saveAndFlush
    model.clear();
    return "redirect:/cat/create";

}

虽然这可行,但我认为不知何故我的百里香表单设置不正确,因此它没有链接,所以欢迎任何人提出解释。

谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    相关资源
    最近更新 更多