最佳Excel导入实践(四)

相关链接
最佳Excel导入实践(一)
最佳Excel导入实践(二)
最佳Excel导入实践(三)
最佳Excel导入实践(四)
最佳Excel导入实践(五)


  上一篇我们讲了Excel导入模板的生成,这一节我们将完成数据导入的功能。整个方案的主要类图如下(图中仅显示出了主要的方法):

  为了做到通用,能满足所有业务单据的导入,我们大量用到了.net的反射技术。如构造订单表头实体的代码大致如下(构建表体的与此类似):

private Object GetHeadEntity(int rowIndex)
{
    HSSFRow row
=sheet.GetRow(rowIndex);
    HSSFCell cell;
    Type cls
=Type.GetType(regulation.HeadClass);
    Object obj
=Activator.CreateInstance(cls);
    PropertyInfo pi;
    Object val;
    
int colIndex;
    
foreach(Column col in regulation.Columns)
    {
        
if(!col.IsEntry)
        {
            
//根据列名找出Excel中对应的列序号
            colIndex=GetExcelColumnIndex(col.ColumnName);
            cell
=row.GetCell(colIndex);
            
//根据Column的数据类型取出Cell中的内容。如果为空将取Column对象中定义的默认值
            val=GetCellValue(cell,col.DataType);
            
//获取实体类中的属性
            pi=cls.GetProperty(col.Property);
            
//给实体类中的属性赋值
            pi.SetValue(obj,val);
        }
    }
    
return obj;
}

执行保存的Execute()方法代码大致如下:

private void Execute()
{
    
int rowsCount = sheet.PhysicalNumberOfRows;
    Object headEntity,entryEntity;
    List 
<object> entries;
    
for (int rowIndex = 0; rowIndex < rowsCount; rowIndex++)
    {
        
if (headEntity == null)
        {
            
//构建表头实体
            headEntity = GetHeadEntity(rowIndex);
            
//构建表体实体
            entries = new List<object>();
            entryEntity 
= GetHeadEntity(rowIndex);
            entries.Add(entryEntity);
        }
        
//检查表头关键字段值是否与下一行相等,如果相等则当同一张单据处理,只用构建表体;如果不等说明是一张新的单据,要先把当前单据保存。
        if (IsSameToNextRow(rowIndex))
        {
            entryEntity 
= GetHeadEntity(rowIndex);
            entries.Add(entryEntity);
        }
        
else
        {
            
//设置分录属性的值
            Type head = Type.GetType(regulation.HeadClass);
            PropertyInfo entryProperty 
= head.GetProperty(regulation.EntryProperty);
            entryProperty.SetValue(headEntity, entries);

            Type clsMethod
=Type.GetType(regulation.MethodClass);
            Object service
=Activator.CreateInstance(clsMethod);
            MethodInfo saveMethod 
= clsMethod.GetMethod(regulation.SaveMethod);
            MethodInfo exValidateMethod 
= clsMethod.GetMethod(regulation.ExValidateMethod);
            
if (exValidateMethod != null)
                
//执行附加的检查方法
                exValidateMethod.Invoke(service, new object[]{headEntity});
            
if (saveMethod != null)
                
//执行保存方法
                exValidateMethod.Invoke(service,new object[]{headEntity});
            
//重置为一张新的单据
            headEntity = null;
            entries 
= null;
        }
    }
}

  最后,细心的读者可能会发现,上面的代码我并没有进行数据有效性验证和出错时的处理。在刚刚不久做的一个系统中,我是将最终的出错信息用动态生成的一张Excel显示的,其显示了和模板结构一样的原始数据和批注的出错信息(正确数据已被导入,不会显示),这样可以直接在这个Excel中对原来的数据进行修改后再直接执行导入,这样做也是为了让用户出错后只用关心出错后的数据,提高可用性。由于有效性验证和出错信息显示相对简单,也不是本方案的重点,所以不作详细说明。

  至此,基本的导入数据功能已经实现。我们发现,基于这个方案对于普通的Excel导入主要的工作就是写那个配置引入规则的XML文件,所以可以轻松实现整个业务系统中所有的导入工作。当然,本方案是以表头表体的案例来进行设计的,对于单表结构稍作修改就可以实现,然而如果要对应一对多的关系,比如一条Excel中的记录要写到多个表中,本设计本不适用,但基本的基于反射的思想是不会变的,如果有需要读者可以自已试试。


 

posted @ 2009-10-24 21:01 atao.xiang 阅读(...) 评论(...) 编辑 收藏