Spring Data Thymeleaf-无法插入相关记录,外键为null

时间:2017-02-28 08:55:36

标签: java hibernate spring-data-jpa thymeleaf

我有2个具有一对多关系的实体。相关的子条目无法插入,因为外键为null。 虽然可以在测试中使用

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

错误

  

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

修改1 :在下面添加详细的错误日志。

  

2017-03-01 09:45:04 DEBUG JpaTransactionManager:759 - 发起   事务提交2017-03-01 09:45:04 DEBUG JpaTransactionManager:512    - 在EntityManager上提交JPA事务[org.hibernate.jpa.internal.EntityManagerImpl@640a6fdf] 2017-03-01   09:45:04 DEBUG 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] as [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]为   [NUMERIC] - [182] 2017-03-01 09:45:04 DEBUG 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]   as [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 INFO AbstractBatchImpl:208 - HHH000010:开   批量发布它仍然包含JDBC语句2017-03-01   09:45:04 DEBUG 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;
    }
}

Thymeleaf表格

<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>

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

控制器

@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;但是想到它,也许它应该是空的,因为Cat尚未保存,所以还没有Id。
  2. 单元测试

    @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 个答案:

答案 0 :(得分:0)

好的,最后我能够解决。事实证明,儿童猫咪没有被添加到猫对象中。

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

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";

}

虽然这有效,但我认为我的百里香叶形式没有正确设置因此它没有联系,所以欢迎任何人提出解释。

感谢。