##  头行保存
           
           
           
头行保存在实用中经常用到，头行保存指的是头表和行表(一对多)的数据同时插入，如中途失败则这次事务不进行提交。

假设我们有两张表 
<style>
table th:first-of-type {
    width: 100px;
}
</style>

**hls_person（头表）**  

|pid|name|age |
|:---: | :---: | :---:|
|1| 张三 | 21  |
| 2 | 李四| 36 |


*hls_hobby（行表**  
|hid| pid |hobby| cause| 
|:--------: | :-----:|:-----: |:-----:|
|1|1|篮球| 因为篮球好玩|
|2|1|游泳| 因为游泳好玩|
|3|1|动画片|最爱看大头儿子|
|4|2|画画|梵高的画也不过如此|


需求是新增一个人的信息以及它的爱好（向hls_person和hls_hobby表新增记录）  
下面是一个头行保存的列子：

```javascript

<script><![CDATA[
//提交数据用到的容器
var viewModel =  kendo.observable({  
    	isEnabled: true,  
	data:{},
	
	mySubmit:function(e){
	    if(e){
	       e.preventDefault();
	    }
	    Hap.submitForm({
                url           : '${base.contextPath}/hls/test/save',
                formModel     : viewModel.data,
                asArray:false,
                grid: { "hobby": $("#grid")
            
                },
                success:function(){
                   showInfoDialog("保存成功!");
                }
            });
            
	},
	function:showInfoDialog(pMessage){
	     kendo.ui.showInfoDialog({
                    title: $l('提示'),
                    message: pMessage
                });
	}
	
    
});

//请求处理方法
function parameterMap(options, type){
        if (type !== "read" && options.models) {
            var datas = options.models
            if (type == 'create' || type == 'update') {
                datas = options.models.map(function(data) {
                    data['__status'] = (type == 'create' ? 'add' : 'update');
                    return data;
                })
            }
            return kendo.stringify(datas);
        } else if (type === "read") {
            var map = {};
            map.page = options.page;
            map.pagesize = options.pageSize;
            for (var k in map) {
                if (map[k] === '' || map[k] === null || map[k] === undefined)
                    delete map[k]
            }
               return Hap.prepareQueryParameter(viewModel.model.toJSON(), options);
        }
}


//属性列是否可编辑
function dsEditable(field){
    return true;
}
]]></script>
```

```xml
<!--头-->
<h:hlsForm title="个人信息" width="100%">
    <h:hlsHBox>
         <h:hlsMaskedTextBox name="name" id="name" bind="enabled: isEnabled, value:model.name" colspan="3" prompt="姓名:" required="true" style="width:100%;"/>
         <h:hlsMaskedTextBox name="age" id="age" bind="enabled: isEnabled, value:model.age" colspan="3" prompt="年龄:" required="true" style="width:100%;"/>
    </h:hlsHBox>
</h:hlsForm>


<!--行-->
<h:dataSource id="dataSource" batch="true" pageSize="10" serverPaging="true">
      <h:transport parameterMap="parameterMap">
        <h:read url="${base.contextPath}/hls/test/query" type="GET" dataType="json"/>
        <h:create url="${base.contextPath}/hls/test/create" type="POST" contentType="application/json" />
        <h:update url="${base.contextPath}/hls/test/save" type="POST" contentType="application/json" />
      </h:transport>
      <h:schema data="rows" total="total" errors="schemaError">
        <h:model id="pid" editable="dsEditable">
           <h:fields>
           </h:fields>
        </h:model>
      </h:schema>
    </h:dataSource>
      <h:hlsGridBox hlsGridId="grid" hlsBtnType="add">
	    <h:hlsGrid id="grid" dataSource="dataSource" selectable="" hlsBtnType="ADD,DELETE" editable="true" height="240">
	      <h:pageable pageSizes="5,10,20,50" buttonCount="2" refresh="true">
	      </h:pageable>
	      <h:columns>
	          <h:column field="hobby" title='爱好' width="150">
		      <h:headerAttributes style="text-align:center"/>
	              <h:attributes style="text-align:center"/>
	          </h:column>
	           <h:column field="cause" title='原因'>
		      <h:headerAttributes style="text-align:center"/>
	              <h:attributes style="text-align:center"/>
	          </h:column>   
	      </h:columns>
	    </h:hlsGrid>
     </h:hlsGridBox>
     
    <!--按钮-->
    <h:hlsToolBar>	 
		<h:hlsButton  click="mySubmit" text="保存"></h:hlsButton>
    </h:hlsToolBar> 
```
      

保存按钮注册了点了事件，点击保存将数据提交到'${base.contextPath}/hls/test/save'

> 在后端controller通过定义	@RequestMapping("/hls/test/save") 注解映射到对应的url,捕获到对应请求。


后端收到前台传过来的数据，调用service层对数据进行持久化。  

controller
```java
	@RequestMapping("/hls/test/save")
	@ResponseBody
	public ResponseData save(HttpServletRequest request,@RequestBody HlsPerson hlsPerson, @RequestParam(defaultValue = DEFAULT_PAGE) final int page,
            @RequestParam(defaultValue = DEFAULT_PAGE_SIZE) final int pagesize){
    		IRequest iRequest = createRequestContext(request);
    		testService.batchChildUpdate(iRequest, hlsPerson ,hlsPerson.getHlsHobby());
	    return new ResponseData();
    }

```

testService的实现类testServiceImpl定义了batchChildUpdate方法:  
```java

	@Override
	public void batchChildUpdate(IRequest iRequest, HlsPerson hlsPerson, List<HlsHobby> hlsHobbyList) {
	    List<HlsPerson> tempHlsPerson = new ArrayList<HlsPerson>();
	    if(hlsPerson != null ){
	        tempHlsPerson.add(hlsPerson);
	        hlsPersonService.batchUpdate(iRequest,tempHlsPerson);
	        Long pid = tempHlsPerson.get(0).getPid();
	        for(HlsHobby hh : hlsHobbyList){
        	    hh.setPid(pid);
        	}
	        hlsHobbyService.batchUpdate(iRequest,hlsHobbyList);
	    }
	   
	    
	}

```

> bathUpdate会根据传入的List对象中单个对象的属性值__status判断，如为update即做更新操作，add为插入操作, __status的值由前端paramter函数决定。