一、问题背景

分账表split_summary结构如下:
create table SPLIT_SUMMARY
(
  uuid                VARCHAR2(32) not null,
  star_tdate          VARCHAR2(26) default '',
  end_date            VARCHAR2(26) default '',
  store_id            VARCHAR2(32) default '',
  order_total_price   NUMBER(13,2) default 0.00,
  product_total_price NUMBER(13,2) default 0.00,
  store_fz_price      NUMBER(13,2) default 0.00,
  shop_fz_price       NUMBER(13,2) default 0.00,
  status              CHAR(1) default '0',
  create_date         VARCHAR2(26) default '',
  note                VARCHAR2(512) default ''
)

商户表store结构如下:

create table STORE
(
  store_id                   VARCHAR2(32) default '' not null,
  store_name                 VARCHAR2(254) default ''
)

两表在Hibernate映射中没有关联关系,split_summary中的store_id可能在store表中,也可能不在,要查询所有的split_summary中的记录以及store中store_id和split_summary表中store_id相匹配的记录。很容易想到在oracle使用左连接进行查询,sql语句如下:

select ss.uuid,ss.store_id, s.store_name  from split_summary ss left join store s on ss.store_id=s.store_id where 1=1 order by ss.uuid desc

二、Hibernate中的左连接查询

Hibernate实战对连接说明如下:



也就是说Hibernate中是不支持on关键字的,如果使用就会报错。Hibernate中的连接条件使用映射关联做的,如下的栗子

Hibernate左连接的栗子
from Item i left join i.bids b with b.amount > 100 where i.description like '%Foo%'

而上述中的split_summary和store在映射中是没有定义关联关系的,怎么解决?


三、解决方案

想到了Hibernate的Native SQL查询

native sql的定义
protected Map<String, Object> getQuerySQL(HttpServletRequest request,
			ActionForm form) {

		OrderSplitForm sform = (OrderSplitForm) form;

		// 构建返回Map
		Map<String, Object> returnMap = new HashMap<String, Object>();
		// 构建参数Map
		Map<String, String> params = new HashMap<String, String>();
		// 编写SQL
		StringBuffer sql = new StringBuffer(
				"select ss.uuid,ss.store_id,s.store_name,ss.SHOP_FZ_PRICE,ss.STORE_FZ_PRICE," +
				"ss.ORDER_TOTAL_PRICE,ss.PRODUCT_TOTAL_PRICE,ss.status,ss.STAR_TDATE,ss.END_DATE," +
				"ss.note from split_summary ss left join store s on ss.store_id = s.store_id where 1=1");
		// 将账单与店铺关联起来, 使用左连接,解决不是商户的问题
//		sql.append(" and ss.storeId = store.id");

		// 店铺编号查询条件
		if (!StringUtil.isEmpty(sform.getStoreId())) {
			sql.append(" and ss.store_Id = :storeId");
			params.put("storeId", sform.getStoreId());
		}

		// 店铺名查询条件
		if (!StringUtil.isEmpty(sform.getStoreName())) {
			sql.append(" and s.store_Name like :storeName");
			params.put("storeName", "%" + sform.getStoreName() + "%");
		}

		// 开始时间查询条件
		if (!StringUtil.isEmpty(sform.getStartDate())) {
			sql.append(" and ss.STAR_TDATE >= :startDate");
			params.put("startDate", sform.getStartDate());
		}

		// 结束时间查询条件
		if (!StringUtil.isEmpty(sform.getEndDate())) {
			sql.append(" and ss.END_DATE <= :endDate");
			params.put("endDate", sform.getEndDate());
		}

		// 分账单状态
		if (!StringUtil.isEmpty(sform.getStatus())) {
			sql.append(" and ss.status = :status");
			params.put("status", sform.getStatus());
		}

		// 按照创建时间倒序排序
		// sql.append(" order by ss.create_Date desc");
		sql.append(" order by ss.uuid desc");

		returnMap.put("sql", sql.toString());
		returnMap.put("param", params);
		return returnMap;
	}

Hibernate中查询的执行
/**
	 *  Native SQL查询
	 * @param nativeSQL  sql
	 * @param map         参数绑定map
	 * @param page        分页查询参数
	 * @param typeMap     标量查询返回类型
	 * @return
	 * @throws Exception
	 */
	public List listByNativeSQL(String nativeSQL, Map<String, Object> map, Pager page, Map<String, Type> typeMap)
			throws Exception {
		List list = null;
		try {
			session = sessionFactory.openSession();

			SQLQuery query = session.createSQLQuery(nativeSQL);
			if (map != null) {
				for (String key : map.keySet()) {
					if (nativeSQL.indexOf(":" + key) != -1) {
						query.setParameter(key, map.get(key));
						System.out.println("param[" + key + "]==="
								+ map.get(key));
					}
				}
			}

			if (typeMap != null) {
				for (String key : typeMap.keySet()) {
					query.addScalar(key, typeMap.get(key));
				}
			}

			if (page != null) {
				query.setFirstResult(page.getFromRow());
				query.setMaxResults(page.getRowsPerPage());
			} else {
				query.setFirstResult(0);
				query.setMaxResults(20);
			}

			list = query.list();

			if (page != null) {
				SQLQuery countQuery = session.createSQLQuery(countSql(nativeSQL));
				if (map != null) {
					for (String key : map.keySet()) {
						if (nativeSQL.indexOf(":" + key) != -1) {
							countQuery.setParameter(key, map.get(key));
							System.out.println("param[" + key + "]==="
									+ map.get(key));
						}
					}
				}
				if (countQuery != null) {
					List countlist = countQuery.list();

					if (countlist != null && countlist.size() > 0) {
						page.setTotalRow(((Number) countlist.get(0)).intValue());
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
			PubLogs.dbLogError(new StringBuffer("获取查询列表失败!").append(
					"PubHibernate.list(nativeSQL)").append(
					"nativeSQL=" + nativeSQL), e);
			throw e;
		} finally {
			if (session != null && session.isOpen()) {
				session.close();
			}
		}
		if (list != null) {
			covertNullToSpace(list);
		}
		return list;
	}

使用createSQLQuery进行Native SQL进行查询。

其中包含了返回参数类型的转换addScalar
if (typeMap != null) {
				for (String key : typeMap.keySet()) {
					query.addScalar(key, typeMap.get(key));
				}
			}

typeMap定义如下

public class SplitSummary extends PubBean {
	// 结算账单开始日期
	private String startDate = "";
	// 结算账单结束日期
	private String endDate = "";
	// 店铺编号
	private String storeId = "";
	// 订单总金额
	private double orderTotalPrice = 0.00;
	// 商品总价
	private double productTotalPrice = 0.00;
	// 店铺分账金额
	private double storeFzPrice = 0.00;
	// 平台分账金额
	private double shopFzPrice = 0.00;
	// 状态
	private String status = "";
	// 创建时间
	private String createDate = "";
	// 备注
	private String note = "";

	/**
	 * nativeSQL查询时返回字段的类型
	 * @return
	 */
	public static Map<String, Type> getTypeMap() {
		Map<String, Type> map = new LinkedHashMap<String, Type>();
		map.put("uuid", Hibernate.STRING);
		map.put("store_id", Hibernate.STRING);
		map.put("store_name", Hibernate.STRING);
		map.put("SHOP_FZ_PRICE", Hibernate.DOUBLE);
		map.put("STORE_FZ_PRICE", Hibernate.DOUBLE);
		map.put("ORDER_TOTAL_PRICE", Hibernate.DOUBLE);
		map.put("PRODUCT_TOTAL_PRICE", Hibernate.DOUBLE);
		map.put("status", Hibernate.STRING);
		map.put("STAR_TDATE", Hibernate.STRING);
		map.put("END_DATE", Hibernate.STRING);
		map.put("note", Hibernate.STRING);
		return map;
	}

	public String getStartDate() {
		return startDate;
	}

	public void setStartDate(String startDate) {
		this.startDate = startDate;
	}

	public String getEndDate() {
		return endDate;
	}

	public void setEndDate(String endDate) {
		this.endDate = endDate;
	}

	public String getStoreId() {
		return storeId;
	}

	public void setStoreId(String storeId) {
		this.storeId = storeId;
	}

	public double getOrderTotalPrice() {
		return orderTotalPrice;
	}

	public void setOrderTotalPrice(double orderTotalPrice) {
		this.orderTotalPrice = orderTotalPrice;
	}

	public double getProductTotalPrice() {
		return productTotalPrice;
	}

	public void setProductTotalPrice(double productTotalPrice) {
		this.productTotalPrice = productTotalPrice;
	}

	public double getStoreFzPrice() {
		return storeFzPrice;
	}

	public void setStoreFzPrice(double storeFzPrice) {
		this.storeFzPrice = storeFzPrice;
	}

	public double getShopFzPrice() {
		return shopFzPrice;
	}

	public void setShopFzPrice(double shopFzPrice) {
		this.shopFzPrice = shopFzPrice;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getCreateDate() {
		return createDate;
	}

	public void setCreateDate(String createDate) {
		this.createDate = createDate;
	}

	public String getNote() {
		return note;
	}

	public void setNote(String note) {
		this.note = note;
	}
}

四、遇到的坑

1、Hibernate中不支持关键字on,连接条件是通过映射关联进行的,例如:映射文件中配置<one-to-many>或者使用注解@OneToMany
2、oracle中表命名别名不能使用as关键字,直接命名即可,例如:split_summary ss

3、addScalar设置返回类型时,要把查询的全部设置,否则设置几个返回几个;还要保证设置参数返回类型的顺序,查询和类型要一致,本例中采用了LinkedHashMap进行设置。


Hibernate中用left join(左外连接)查询映射中没有关联关系的两个表记录问题的更多相关文章

  1. SQL 左外连接查询 将右表中的多行变为左表的一列或多列

    示例: --行列互转 /**************************************************************************************** ...

  2. oracle——外连接查询

    一.问题描述 有时我们为了保留某个表中的数据,而该表中的数据在另外一个关联表中未必都存在对应,此时就应该试用外连接查询. 比如:两个表,产品表和子产品表 注:子产品的parent_product_id ...

  3. [原创]java WEB学习笔记91:Hibernate学习之路-- -HQL 迫切左外连接,左外连接,迫切内连接,内连接,关联级别运行时的检索策略 比较。理论,在于理解

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. Hibernate迫切左外连接和迫切内连接

    •迫切左外连接: •LEFT JOIN FETCH 关键字表示迫切左外连接检索策略. –list() 方法返回的集合中存放实体对象的引用, 每个 Department 对象关联的 Employee  ...

  5. [原创]java WEB学习笔记88:Hibernate学习之路-- -Hibernate检索策略(立即检索,延迟检索,迫切左外连接检索)

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  6. 在查询用户的权限的时候 使用左外连接 和 access数据库中左外连接

    一般做视图最好是做成左外连接的.而其作用尤其在我们查询用户当前的权限时尤为明显,我们将 权限表即模块表放→角色权限表→角色表→用户角色表→用户表 就这样left outer join 连接起来,这样就 ...

  7. 内连接、左外连接、右外连接、全外连接、交叉连接(CROSS JOIN)-----小知识解决大数据攻略

    早就听说了内连接与外连接,以前视图中使用过.这次自考也学习了,只是简单理解,现在深入探究学习(由于上篇博客的出现)与实践: 概念 关键字: 左右连接 数据表的连接有: 1.内连接(自然连接): 只有两 ...

  8. Mysql数据库左外连接,右外连接,模糊查询

    内连接,左外连接,右外连接都是数据库的常用连接与使用手段 内连接 select * from assets_car c inner join category c on a.id = c.id; 左外 ...

  9. mysql——多表——外连接查询——左连接、右连接、复合条件查询

    ), d_id ), name ), age ), sex ), homeadd ) ); ,,,'nan','beijing'); ,,,'nv','hunan'); ,,,'nan','jiang ...

随机推荐

  1. 20145321 《Java程序设计》第3周学习总结

    20145321 <Java程序设计>第3周学习总结 教材学习内容总结 第四章 4.1 类与对象 1.定义类:类定义时用关键词 class. 一个原始码中可以有多个类定义,但只能有一个公开 ...

  2. 起源游戏临时实体(Temp Entity)

    如何查看实体 https://wiki.alliedmods.net/Temp_Entity_Lists_(Source) 这里是部分游戏的临时实体列表 # 还可以通过在游戏内输入来获取游戏的临时实体 ...

  3. [BZOJ3733]Iloczyn

    Description 给定正整数n和k,问能否将n分解为k个不同正整数的乘积 Input 第一行一个数T(T<=4000)表示测试组数 接下来T行每行两个数n(n<=10^9),k(k& ...

  4. [BZOJ3174]拯救小矮人

    Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个小矮人, ...

  5. js去除前后空格

    <script language="javascript"> String.prototype.trim=function(){     return this.rep ...

  6. OAuth客户端调用

    public class OAuthClientTest { private HttpClient _httpClient; public OAuthClientTest() { _httpClien ...

  7. vue.js的一些事件绑定和表单数据双向绑定

    知识点: v-on:相当于: 例如:v-on:click==@click ,menthods事件绑定 v-on修饰符可以指定键盘事件 v-model进行表单数据的双向绑定 <template&g ...

  8. 数据结构实习 - problem K 用前序中序建立二叉树并以层序遍历和后序遍历输出

    用前序中序建立二叉树并以层序遍历和后序遍历输出 writer:pprp 实现过程主要是通过递归,进行分解得到结果 代码如下: #include <iostream> #include &l ...

  9. GridControl 史上最全的资料(一)

    GridControl详解(一)原汁原味的表格展示 Dev控件中的表格控件GridControl控件非常强大.不过,一些细枝末节的地方有时候用起来不好找挺讨厌的.使用过程中,多半借助Demo和英文帮助 ...

  10. Class 的基本语法

    简介 JavaScript 语言中,生成实例对象的传统方法是通过构造函数.下面是一个例子. function Point(x, y) { this.x = x; this.y = y; } Point ...