随笔-35  评论-97  文章-0  trackbacks-0

EasyDBO上对象关联还是存在很大问题。

其中一个,添加对象时,没能将被关联对象的主键(由数据库生成)插入到关联对象的外键上。

注:

(1) EasyDBO的一对一关联中,外键在关联对象方。

Class A{

.....

B b ;

}

 

Class B{

}

对应于实体A的数据库表有外键,如 fk_b

 

(2) EasyDBO的一对多关联中,外键在被关联对象方(多方)。

Class A{

.....

List<B> bList ;

}

 

Class B{

A a;

}

对应于实体B的数据库表有外键,如 fk_a

 

在解决这个问题中,对源码做一些的修改:

1、首先解决如果是数据库生成的主键(如auto_increment类型),在DatabaseDAO添加getGeneratedKey()方法。

    public Serializable getGeneratedKey()
    
{
        
if(prepared==null){
            
return null;
        }

        Serializable ret 
=null;
        ResultSet rs 
= null;
        
try
        
{
            rs 
= prepared.getGeneratedKeys();
            
if(rs.next())
            
{
                ret 
= (Serializable)rs.getObject(1);
                logger.info(
"get the GeneratedKey:" + ret);
            }

        }

        
catch(SQLException e)
        
{
            e.printStackTrace();
        }

        
finally
        
{
            
if(rs != null)
                
try
                
{
                    rs.close();
                }

                
catch(SQLException e)
                
{
                    e.printStackTrace();
                }

        }

        
return ret;
    }

2、在EasyJDBEngine中添加generatedKey字段和getter方法。

    private Serializable generatedKey;
    
    
    
public Serializable getGeneratedKey()
    
{
        
return generatedKey;
    }

   在EasyJDBEngine的public boolean add(DBObject obj)方法中try的括号末尾添加

generatedKey  = dba.getGeneratedKey();

    public boolean add(DBObject obj) // 添加一个对象
        ...
        
try {

                    ...... 
            generatedKey  = dba.getGeneratedKey();
        }
 catch (Exception e) {

3、EasyJDB中添加以下方法:

    private Object setObjectGenIdValue(Object obj){
        BeanWrapper wrapper 
= new BeanWrapper(obj);
        DBTable dbTable 
= findTable(obj.getClass());
        String idFieldName 
= dbTable.getPoperty(dbTable.getId());
        
if(wrapper.getPropertyValue(idFieldName)==null && StringUtils.isNotEmpty(dbEngine.getGeneratedKey())){
            Object javaPropertyValue 
= wrapper.convertIfNecessary(String.valueOf(dbEngine.getGeneratedKey()),
                                                                    dbTable.getType(idFieldName));
            wrapper.setPropertyValue(idFieldName, javaPropertyValue);
            System.out.println(
"setting id.");
            
return javaPropertyValue;
        }

        
return null;
    }


    
private Object getObjectIdValue(Object obj){
        BeanWrapper wrapper 
= new BeanWrapper(obj);
        DBTable dbTable 
= findTable(obj.getClass());
        String idFieldName 
= dbTable.getPoperty(dbTable.getId());
        
if(StringUtils.isNotEmpty(wrapper.getPropertyValue(idFieldName))){
            
return wrapper.getPropertyValue(idFieldName);
        }

        
return null;
    }


    
private void setClassFieldValue(Object target,ClassField classField,Object value){
        BeanWrapper wi
=new BeanWrapper(target);
        DBTable dbTable 
= findTable(target.getClass());
        wi.setPropertyValue(dbTable.getPoperty(classField.getColumn()),value);
    }

EasyJDB中的public boolean add(Object obj)方法改为:

    public boolean add(Object obj)
    
{
        logger.debug(
"把对象obj保存到数据库中");
         
boolean ret = dbEngine.add(obj2dbo(obj));
         setObjectGenIdValue(obj);
///如果是新添加的记录,且主键为数据库生成,那么将主键值返回赋给对象
         if(ret)ret = ret & addRelativeObject(obj);
        
return ret;
    }

 

 EasyJDB中的private boolean addRelativeObject(Object obj)方法改为:

 

    private boolean addRelativeObject(Object obj)
    
{
        
boolean ret = true;
        DBTable table 
= findTable(obj.getClass());
        
if(table != null)
        
{
            BeanWrapper wrapper 
= new BeanWrapper(obj);
            java.util.Iterator it 
= table.getClassField().entrySet().iterator();
            
while(it.hasNext())
            
{
                
// 尝试处理其它字段
                Map.Entry en = (Map.Entry)it.next();
                String propertyName 
= (String)en.getKey();
                ClassField classField 
= (ClassField)en.getValue();
                
// System.out.println(classField.getClass()+":"+propertyName);
                if(classField instanceof ManyToManyField && wrapper.isReadableProperty(propertyName))
                
{
                    
// 处理多对多
                    Object value = wrapper.getPropertyValue(propertyName);
                    
// System.out.println("值内容"+value.getClass());
                    if(value != null && value instanceof Collection)
                    
{
                        java.util.Iterator es 
= ((Collection)value).iterator();
                        
while(es.hasNext())
                        
{
                            Object element 
= es.next();
                            ret 
= ret & this.saveOrUpdate(element);
                            
// 保存关联的第三方表
                            ManyToManyField field = (ManyToManyField)classField;
                            
/*
                             * DBTable table2=findTable(element.getClass());
                             * if(table2!=null) { ManyToManyField field2=null;
                             * java.util.Iterator
                             * inf2=table2.getClassField().values().iterator();
                             * while(inf2.hasNext()) { ClassField
                             * ff=(ClassField)inf2.next();
                             * if(ff.getTableName().equals(field.getTableName()) &&
                             * ff.getType()==obj.getClass()) {
                             * field2=(ManyToManyField)ff; } }
                             
*/

                            String sql 
= "insert into " + field.getTableName() + "(" + classField.getColumn() + ","
                                            
+ field.getTagColumn() + ") values(?,?)";
                            java.util.Collection paras 
= new java.util.ArrayList();
                            paras.add(wrapper.getPropertyValue(classField.getKey()));
                            BeanWrapper wrapper2 
= new BeanWrapper(element);
                            paras.add(wrapper2.getPropertyValue(field.getTagKey()));
                            
try
                            
{
                                
this.execute(sql, paras);
                            }

                            
catch(Exception e)
                            
{
                                logger.error(
"插入多对多关系时出错!");
                                e.printStackTrace();
                            }

                            
// }
                        }

                    }

                }

                
else if((classField instanceof ManyToOneField) && wrapper.isReadableProperty(propertyName))
                
{
                    
// 处理一对多
                    Object value = wrapper.getPropertyValue(propertyName);
                    
if(value != null && value instanceof Collection)
                    
{
                        java.util.Iterator es 
= ((Collection)value).iterator();
                        
while(es.hasNext())
                        
{
                            Object item 
= es.next();
                            setClassFieldValue(item,classField,obj);
//设置关联值
                            ret = ret & this.saveOrUpdate(item);
                        }

                    }

                }

                
else if((classField instanceof OneToOneField) && wrapper.isReadableProperty(propertyName))
                
{
                    
// 处理一对一
                    Object value = wrapper.getPropertyValue(propertyName);
                    
if(value != null)
                    
{
                        ret 
= ret & this.saveOrUpdate(value);
                        
if(StringUtils.isNotEmpty(getObjectIdValue(value)))
                        
{
                            setClassFieldValue(obj, classField, value);
//设置关联值
                            update(obj);//更新一下数据,将关联的对象主键作为外键
                        }

                    }

                }

            }

        }

        
return ret;
    }

EasyJDB中的public boolean update(Object obj)方法改为:

    public boolean update(Object obj)
    
{
        logger.info(
"更新持久层中的数据表对象");
        
boolean ret = dbEngine.update(obj2dbo(obj));
//        ret = ret & this.addRelativeObject(obj);//这句很容易会导致死循环,先不要了
        return ret;
    }

EasyJDB中的public boolean saveOrUpdate(Object obj)方法改为:

    public boolean saveOrUpdate(Object obj)
    
{
        
// logger.info("把对象持久化到数据库中,先偿试添加,若无法保存则执行修改操作");
        boolean ret = false;
        
try
        
{
            Object id 
= getObjectIdValue(obj);
            
            
if(id == null)
            
{
                ret 
= add(obj);
            }


            
else
            
{
                
if(get(obj.getClass(), id) != null)
                    ret 
= update(obj);
                
else
                    ret 
= add(obj);
            }

        }

        
catch(Exception e)
        
{
            
//这里的也先不要的,很容易导致死循环
            
// 出错,进一步尝试使用原始的方法进行更改
//            if(add(obj))
//            {
//                return true;
//            }
//            return update(obj);
            e.printStackTrace();
        }

        
return ret;
    }

 

解释一下:

这里处理的不包括多对多的关系,很少用到,暂时不管。

解决的思路是,如果是自增(数据库生成的id),那么获取这个id,并回赋给对象,对象有了主键值(每个这样的对象都回赋主键值),关联就有了导航。

在一对一关系处理中,因为是先插入关联对象数据,然后在插入被关联对象数据。但是关联对象需要知道被关联的主键值,而被关联的主键值是在最后插入数据后回赋的,所以,采取从新将对象关联,并更新数据。

       setClassFieldValue(obj, classField, value);//设置关联值
       update(obj);//更新一下数据,将关联的对象主键作为外键

在处理一对多(也即多对一)关系中,如一开就提到的“EasyDBO的一对多关联中,外键在被关联对象方(多方)”,数据插入顺序同一对一的一样,先关联对象,后被关联对象,所以,在这里只需要在被关联对象插入前更新关联就可以了

setClassFieldValue(item,classField,obj);//设置关联值

比较明显,将一对多的关系转换成了多个一对一了。或许这样不是很好,但是,在原有的架构上,比较难做更大修改。

 

EasyDBO有一些主键生成器的,不知对对象关联上主键的处理上有没有独特的解决方法,待探索...

浅见,不当的地方欢迎指正~~~~~~~~

posted on 2007-07-02 18:15 三告习习 阅读(1152) 评论(3)  编辑  收藏 所属分类: easyJF-projects

评论:
# re: [EasyDBO] EasyDBO上对象关联问题的一个简单解决方法 2007-07-19 12:13 | hingwu
我在前面的项目中也使用到了EasyJDB,也发现了不少bug,有些甚至是莫名其妙的错误,希望以后有得提升。  回复  更多评论
  
# re: [EasyDBO] EasyDBO上对象关联问题的一个简单解决方法 2007-07-19 17:29 | John Ong
这种shit framework 不用也罢!  回复  更多评论
  
# re: [EasyDBO] EasyDBO上对象关联问题的一个简单解决方法 2007-07-19 21:44 | 三告习习
@John Ong
尽管不是很完善,从中还能学到多少东西的,至少能提醒自己写的时候不要这样冒险,在处理这些地方需要慎重些
  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: