【專案問題總結】4:修改操作的重複性驗證邏輯

連江偉發表於2016-06-05

問題描述:

        在做基礎系統的Bug除錯及修改的過程中,遇到了一個很奇怪的問題:在進行記錄的修改操作時,如下圖所示,


        理論上層次名稱和備註都是可以隨意修改的,但是如果我只是修改備註,對名稱不做任何的改動(或者是隻是點開修改的彈出框,不做任何改動),點選確定進行提交,總是彈出層次名稱重複的提示,導致修改失敗。

問題分析:

        經過各種測試,發現問題就出在這個名稱是否重複的判斷邏輯上,開啟程式碼進行檢視,找到驗證層次名稱是否重複的程式碼,如下所示:

public String validateLevelName(String levelName, String dataBaseName)
			throws Exception {
		Map<Serializable, Serializable> map = new HashMap<Serializable, Serializable>();
		List<SchoolLevel> classlist = new ArrayList<SchoolLevel>();
		String result;
		classlist = schoolLevelBean.queryLevelNodeByName(levelName,dataBaseName<span style="font-family: Arial, Helvetica, sans-serif;"> );</span>
		if (classlist == null || classlist.isEmpty()) {
			// 無重複資料
			result = "0";
		} else {
			// 有重複資料
			result = "1";
		}
		return result;
	}

        其呼叫的queryLevelNodeByName  方法如下

<span style="font-size:18px; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="java">public List<SchoolLevel> queryLevelNodeByName(String condition,
			String dataBase) {

		String hql = "from SchoolLevel h where h.levelName=:levelName and h.isDelete=0";
		Map map = new HashMap();
		map.put("levelName", condition);
		

		// 呼叫底層 Hql查詢方法
		return schoolLevelEao.queryByHql(hql, map, dataBase);
	}

       從上面的程式碼可以看到,判斷名稱是否重複的方法中只是根據名稱進行了查詢,判斷返回結果是否為空,即得出是否重複的結論,這個邏輯是不對的,為什麼這麼說呢?因為既然是修改操作,那麼載入出來的這條記錄在資料庫中是存在的,然後用已經存在的名稱作為引數去資料庫進行查詢,結果肯定能查到至少一條,而查詢結果返回的資料就是頁面載入出來的那條記錄,以這樣的邏輯去進行判斷是否重複,其結果將永遠是“對不起,層次名稱已經存在,請返回修改!”。 

        怎麼辦呢?最開始的想法是,既然是修改那麼沒必要進行重複判斷了,只有在新增的時候,進行重複性判斷即可。可是修改程式碼之後,發現還是不行,上述問題是沒了,又出來新的問題,出現了重複記錄,因為沒有進行重複性校驗,名稱可以肆無忌憚的重複了,回頭一想這方法真是too young too simple!

      後來才開始認真的尋找解決辦法,其核心問題是在進行重複性校驗的時候,將要修改的這條記錄本身排除即可。如何排除呢?我想到的有兩種思路,一種是在查詢語句上進行修改,在查詢條件上新增“id <> 要修改記錄的id”。另一種是,在查詢結果中將被修改的記錄排除,如果排除提交的記錄,查詢結果集還有記錄,那就證明和其自身除外的其他記錄的名稱重複了。

問題解決:

        思路有了,那麼就著手開始修改程式碼邏輯吧,先嚐試了第一種辦,修改查詢的JPQL語句,因為對JPQL語句不怎麼熟悉,雖然類似於HQL,但是還是還是有些區別,我知道第一種方法簡單,但是沒有去深究,最後也沒成功。因此就改用第二種方法進行實現,經過了反覆的測試和修改,終於是成功了,其程式碼如下:

public String validateLevelName(String levelName,String levelID, String dataBaseName)
			throws Exception {

		Map<Serializable, Serializable> map = new HashMap<Serializable, Serializable>();
		List<SchoolLevel> levelIdList = new ArrayList<SchoolLevel>();
		List<SchoolLevel> classlist = new ArrayList<SchoolLevel>();
		String result = "";
		//根據提交的Id進行查詢
		levelIdList = schoolLevelBean.queryLevelIDByHql(levelID, dataBaseName);
		//根據提交的名稱進行查詢
		classlist = schoolLevelBean.queryLevelNameByHql(levelName,dataBaseName);//classlist:  0   1
		
		//根據Id查詢的記錄條數大於0是修改的重複判斷邏輯,否則就是新增的判斷邏輯
		if(levelIdList.size()>0){ //修改的判斷邏輯
			//同一Id下,如果提交的名稱和資料庫查詢出來的名稱相同,則不重複
			if(levelIdList.get(0).getLevelName().equals(levelName)){
				result="0";
			}else{
				//如果名稱做了改動,則將按名稱查詢的結果中的記錄本身排除
				for(int i=0;i<classlist.size();i++){
					if (classlist.get(i).getId()==levelID) {
						classlist.remove(i);
					}
				}
				//判斷移除其自身之後的記錄條數是否為0
				if (classlist.size()==0) { //若為0,則不重複
					result = "0";
				} else {    //否則重複
					result = "1";
				}
			}
			
		}else{ //新增的判斷邏輯
			if(classlist.size()>0){
				result="1";
				
			}else{
				result="0";
			}
		}
	
		
		return result;
	}

        因為新增和修改的名稱是否重複都要用這個函式,因此就將兩者判斷邏輯放在了一起,有些許繁瑣。雖然我實現了功能效果,但是心裡明白這種實現還可以再優化,並且這種絕不是最優的實現方案,希望大家有好的解決方案可以給我留言,不勝感激。

相關文章