增:
1、当一个对象有id值,如果数据库有这个id,你在create时执行的是保存操作,没有这个id,执行新建操作
2、use与coupon之间有一个中间表usercoupon,下面这种添加usercoupon的方式会使与user对应的usercoupon的创建时间都会刷新,就像新建一样
user.getCoupons().add(coupon);
userService.save(user);
所以下面这种方式好一点
UserCoupon uc=new UserCoupon(); uc.setCoupon(coupon); uc.setUser(user); userCouponService.create(uc);
查:在一次查询类别表Type的所有对象,查询花了很长时间,发现不仅查了Type,还将type的set<SubType>属性赋值,即又查了SubType表
,SubType的set<Store>,Store的set<Coupon>........做了很多无用功,但是虽然配置了openSessionInViewFilter,但是这些set都是lazy加载啊
调试发现
(1)执行下面方法只查询了Type表
@Override public List<T> listAll() { // TODO Auto-generated method stub String hql="from Type type where type.deleted=false "; return list(hql, null); }
(2)执行到以下代码时,开始疯狂查询和加载response.setObject(list);
List<Type> list = typeService.listAll(); response=new Response(0); response.setObject(list);
原因:在setObject(list)的过程中,元素Type的set属性被初始化,并且从表填充数据
(3)解决方法一
List<Type> list = typeService.listAll(); response=new Response(0); for(int i=0;i<list.size();i++){ list.get(i).setSubs(null); } response.setObject(list);
解决方法二:只从查询结果区部分需要用到的字段,然后拼成一个新的对象返回
coupons=couponService.list("select new Coupon(coupon.id,coupon.name) from Coupon coupon where coupon.store.id=:id Order by name", map);
条件是有相应的构造函数(加了这个,还会org.hibernate.InstantiationException: No default constructor for entity:)
所以还加个无参构造函数
public Coupon(int id,String name) { super(); this.name = name; this.setId(id); }
改:修改优惠券coupon类
/** * @author JL 优惠券实体类 */ @Entity @Table(name = "tb_coupon") public class Coupon extends BaseBean{ /** * 编码 */ private String code; /** * 优惠券名称 */ private String name; /** * 优惠券所属商家 */ @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, fetch = FetchType.LAZY) @JoinColumn(name = "store_id") private Store store; @ManyToMany(mappedBy="coupons",fetch = FetchType.LAZY,cascade=CascadeType.ALL) private List<User> users=new ArrayList<User>(); @OneToOne @PrimaryKeyJoinColumn private CouponAd ad; }
Store关于coupon的配置
@OneToMany(mappedBy = "store", fetch = FetchType.LAZY) private Set<Coupon> coupons = new HashSet<Coupon>();
表单文件jsp需要传入一个coupon的各个属性,包括外键:coupon.store.id
保存修改的代码
couponService.save(coupon);
注意:
(1)如果成员store有值,却没有提交coupon.store.id,则保存后store为null
(2)如果成员store本身为null,你提交了coupon.store.id希望自动给他赋上store的值,那么save会报错:
transient 瞬时态
org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: com.life.hibernate.bean.Store; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.life.hibernate.bean.Store
这时需要
coupon.setStore(storeService.find(Store.class, coupon.getStore().getId())); couponService.save(coupon);
(3)如果coupon.id的值没有传过去,很严重,这时不是保存,而是新建一条记录
Done