2017-07-16 46 views
5

这是我的模型类语法不好SQL异常,而使用读取值的RowMapper

//Model 

    public class CustomerData { 

     private String locomotive_id; 
     private String customer_name; 
     private String road_number; 
     private String locomotive_type_code; 
     private String in_service_date; 
     private String part_number; 
     private String emission_tier_type; 
     private String airbrake_type_code; 
     private String lms_fleet; 
     private String aar_road; 
     private String locomotive_status_code; 

     // Getters and Setters 

这里是我的RowMapper实现

//RowMapper 

    public class CustomerDataResponseMapper implements RowMapper { 

    @Override 
    public Object mapRow(ResultSet rs, int count) throws SQLException { 
     CustomerData customerData = new CustomerData(); 

     customerData.setLocomotive_id(rs.getString("locomotive_id")); 
     customerData.setCustomer_name(rs.getString("customer_name")); 
     customerData.setRoad_number(rs.getString("road_number")); 
     customerData.setLocomotive_type_code(rs.getString("locomotive_type_code")); 
     customerData.setIn_service_date(rs.getString("in_service_date")); 
     customerData.setPart_number(rs.getString("part_number")); 
     customerData.setEmission_tier_type(rs.getString("emission_tier_type")); 
     customerData.setAirbrake_type_code(rs.getString("airbrake_type_code")); 
     customerData.setLms_fleet(rs.getString("lms_fleet")); 
     customerData.setAar_road(rs.getString("aar_road")); 
     customerData.setLocomotive_status_code(rs.getString("locomotive_status_code")); 

     return customerData; 
    } 

} 

最后,我得到了我DaoImpl类在这里

//DaoImpl 
    public String getCustomersData(String locoId, String custName, String roadNumber) { 
     CustomerData resultSet = null; 
     String str = ""; 
     if (locoId != null && locoId.length() > 0 && !(locoId.equals("0"))) { 
      str = "select locomotive_id,customer_name,road_number,model_type as locomotive_type_code,to_char(in_service_date,'yyyy-mm-dd') as in_service_date,loco_part_number as part_number, emission_tier_type as emission_tier_type, " 
        + "air_brake_type as airbrake_type_code,lms_fleet,aar_road,locomotive_status_code from get_rdf_explorer.get_rdf_locomotive_detail where locomotive_id = ?"; 
      resultSet = (CustomerData) jdbcTemplate.queryForObject(str, new CustomerDataResponseMapper(), locoId); 
     } else if ((custName != null && custName.length() > 0) 
       && (roadNumber != null && roadNumber.length() > 0 && roadNumber != "0")) { 
      str = "select locomotive_id,customer_name,road_number,model_type as locomotive_type_code,to_char(in_service_date,'yyyy-mm-dd') as in_service_date,loco_part_number as part_number, emission_tier_type as emission_tier_type, " 
        + "air_brake_type as airbrake_type_code,lms_fleet,aar_road,locomotive_status_code from get_rdf_explorer.get_rdf_locomotive_detail where customer_name = ? and road_number= ?"; 
      resultSet = (CustomerData) jdbcTemplate.queryForObject(str, new CustomerDataResponseMapper(), custName, roadNumber); 
     } else { 
      str = "select distinct customer_name from get_rdf_explorer.get_rdf_locomotive_detail order by customer_name asc"; 
      resultSet = (CustomerData) jdbcTemplate.queryForObject(str, new CustomerDataResponseMapper()); 
     } 
     return resultSet.toString(); 
    } 

我怎样才能有条件地从resultSet中获取值是基于特定的列是否被pres或者不在结果集中。由于我没有通过我的查询获得所有列。

当特定列不存在于resultSet中时,我正在收到SQL错误的语法异常。例如,当获得不同客户名称的第三个查询得到执行时,在resultSet中,只有customerName将存在,但不包含其他列。

这将非常有帮助。提前致谢。

+0

欢迎来到Stack Overflow!寻求调试帮助的问题(“为什么这个代码不工作?”)必须在问题本身中包含所需的行为,特定的问题或错误以及必要的最短代码**。没有明确问题陈述的问题对其他读者无益。请参阅:[如何创建最小,完整和可验证示例](http://stackoverflow.com/help/mcve)。 –

+0

@JoeC由于这是我的项目特定的代码,我不能发布完整的代码。 –

+0

那么_specific问题或error_?更不用说_ **最短的代码必要_? –

回答

0

如果列数不确定,那么您应该根据其实现使用ColumnMapRowMapper,即使您不需要单独创建RowMapper的具体类别(即,CustomerDataResponseMapper),你只需要传递的查询ColumnMapRowMapper实例给出如下:

ColumnMapRowMapper rowMapper = new ColumnMapRowMapper(); 
List<Map<String, Object>> customerDataList = jdbcTemplate.query(sql,rowMapper, args); 

现在你应该创建一个方法来处理这个地图像

private CustomerData fillCustomerDataFromMap(List<Map<String, Object>> customerDataList){ 
      CustomerData customerData = new CustomerData(); 

      for(Map<String, Object> map: customerDataList){ 

       customerData.setColumn(map.get("columnName")); 
       customerData.setColumn(map.get("columnName")); 
       customerData.setColumn(map.get("columnName")); 
       customerData.setColumn(map.get("columnName")); 

......... 
......... 
......... 
      } 
     return customerData; 
    } 

这是更具可读性和删除样板代码并且如果列名不存在于地图中则不会抛出任何异常(如果列名不在地图中,它将简单地返回null

ColumnMapRowMapper的引用:

https://github.com/spring-projects/spring-framework/blob/master/spring-jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java

+0

完美,这就是我一直在寻找。有没有工作的例子? –

+0

嗨,@ Santosh Anantharamaiah这应该毫无疑问地工作,因为我们只使用了类的spring jdbc库就是这样。 –

1

我的建议是用三种不同的方法拆分你的getCustomersData。如果你一定要忽略这个建议,那么这个快速和肮脏的解决方案是保护rowmapper中的rs.getString(...)调用。事情是这样的:

try { 
    customerData.setLocomotive_id(rs.getString("locomotive_id")); 
} catch (SQLException e) { 
    // ignore this exception. DO NOT TRY THIS AT HOME! 
} 
+0

https://stackoverflow.com/questions/3599861/how-can-i-determine-if-the-column-name-exist-in-the-resultset#这就是我密切关注的。对这种情况使用例外可能不是正确的选择权? –

+0

当然,正如我写的,这是一个“快速和肮脏”的解决方案。你最好重构你的设计。 – aaguilera

+0

嗨,@aaguilera这个解决方案是昂贵和费时的,你可以阅读更多关于如何缓慢的Java异常[这里](http://www.fuwjax.com/how-slow-are-java-exceptions/) –

1

您可以使用它调查了ResultSet的列

@SuppressWarnings("unchecked") 
public <T> T getColIfPresent(ResultSet rs, String columnName) throws SQLException { 
    ResultSetMetaData metaData = rs.getMetaData(); 
    for (int i = 1; i <= metaData.getColumnCount(); i++) { 
     if (columnName.equals(metaData.getColumnName(i))) { 
      return (T) rs.getObject(columnName); 
     } 
    } 
    return null;// not present 
} 

然后,在排映射器的通用方法。

customerData.setLocomotive_id(getColIfPresent(rs, "locomotive_id")); 
... 

这具有O(n * m个)复杂其中Ñ - 检查列数, - 在ResultSet返回的列的数目。

如果您选择忽略SQLException,至少记录它在案件SQLException不同的亚型出现,因此,它不是失去了DEBUGTRACE水平。

+0

我完全同意你的观点,但它肯定会影响业绩吗?因为它必须检查列,然后返回并分配值。 –

+0

我建议将调查列存储在行映射器的私有属性中,作为'Set columns'。然后在第一行填充“ResultSet”的列,其他行将只包含一个检查if(columns.contains(columnName)){..}'检查这个集合,它是O( 1)。这种方式列每个查询只确定一次,而不是每行。 – isah

6

由于您已经有3个单独的查询,为什么没有3个单独的RowMapper s,每个查询一个。您的查询“知道”他们返回的列,因此您可以轻松地为RowMapper创建这些类。

如果您确实需要高保真解决方案,您可以为公共部分创建抽象基础RowMapper,并为查询指定部分创建3个子类。

+0

让我们考虑每个查询中只有几个不同的列名,这不会违背DRY原则。在3个不同的地方重复同一段代码。 –

+2

您可以使用常见的超类共同部分。但在我看来,DRY是一个很好的原则,但并不是无处不在。在这里,你有3个单独的查询,最有可能会演变成彼此更不同。这些都是简单的类,并且它具有不同的RowMappres的可读代码,而不是尝试创建一些自动魔术,而这些自动魔法之后没有人能够理解。 – ikettu

1

而不是conditionnaly获取列,你可以修改你的SQL来匹配你的映射器,比如将其他字段设置为空字符串或null(如果getString()在null或其他东西上崩溃,我不会remmember)。

例如你的第三个查询看起来像:

select distinct customer_name, null as "locomotive_id",'' as "road_number", null as model_type, [etc.] from get_rdf_explorer.get_rdf_locomotive_detail order by customer_name asc 

因此,每个查询将具有相同的列,你不必去适应。如果您确实想要/不能更改rowMapper(或者只想为此对象添加一个),那么这就是解决方案。

但老实说,我会去与ikketu的解决方案。你应该为第三个查询制作一个单独的映射器(加上它不会很复杂)。不使用ORM是一种选择,但无论如何你都会有冗余问题。我甚至会补充说,你应该分开代码中的一些逻辑,这个方法似乎做了不同的事情(业务逻辑取决于输入和数据库访问),它不是很清楚(在第三个之后,创建一个像“ getdistinctName()“或其他)。

1

Santosh,一个快速的解决方法可能会传递一个标志给你的rowmapper,同时将它提供给jdbcTemplate。我做了很多次,以避免多个rowmapper。 resultSet =(CustomerData)jdbcTemplate.queryForObject(str,new CustomerDataResponseMapper(1),custName,roadNumber);

对于上述更改,您需要使用默认构造函数重载构造函数。然后,您需要在mapRow()方法中使用您的标志即实例变量分别处理每种情况。

0

根据您的查询,我看到,在get_rdf_explorer.get_rdf_locomotive_detail执行SQL查询之前,也有一些记录,并获得必要的(唯一的)记录的3个选项都是可能的逻辑:

  1. 通过locomotive_id
  2. 通过customer_nameroad_number
  3. 任何记录(所有记录必须有相同的customer_name,否则SQL distinct不附加任何条件返回超过1行)

因此,在第三选项,您可以得到任何1所记录的所有属性等于NULLNOT NULLcustomer_name值:

str = "select null as locomotive_id, customer_name, null as road_number,  
<other attributes> from get_rdf_explorer.get_rdf_locomotive_detail where 
rownum = 1";` 
+0

与我的回答没有什么不同。 – Asoub

1

您可以使用BeanPropertyRowMapper这将直接映射目标类的字段名。这里是javadoc

这些名称可以直接匹配,也可以通过使用“camel”情况将名称分隔的部分与下划线相同的名称进行匹配。所以,只要你想直接映射到一个类,就可以使用它。只需确保选定的字段保留在目标类中。而是一个默认或无参数的构造函数。

下面的例子使用BeanPropertyRowMapper

RowMapper<CustomerData> mapper = new BeanPropertyRowMapper<>(CustomerData.class); 
List<CustomerData> result = jdbc.query("your query string...", mapper, query_args...); 

,那么你可以返回第一个对象或任何获得CustomerData

+0

嗨,@zico我不认为这将有助于列数不确定 –

+0

@IrfanBhindawala你说什么意思是未定数列?尽管'BeanPropertyRowMapper'自动将选定的列与目标类的属性进行映射。如果他选择一个字段并将其呈现在具有多个属性的目标类中,则它将仅绑定(仅调用默认设置器)一个字段。 – Zico

+0

'BeanPropertyRowMapper'将如何决定调用哪个类的设置器,以及默认设置器的意思是什么 –