最近完成了公司内部CRM,感觉收获不少,拿出来给大家分享一下,也方便日后查看有些地方可能说的不太准确,还请大家指教。 总的说来有以下五条: 1.读取Excel文件中数据并放到DataTable中; 2.快速找出DataTable中的重复行; 3.比较Excel文件中重复行时遇到的问题; 4.对“i++”和“i++”的重新认识; 5.尝试利用事务来插入数据; 解析: 对于第1条,我是从网上找的,发现网上98%都是采用oledb方式实现,我稍微改造了一下,代码如下:
public override DataTable GetUserDataDTList(string excelPath)
{
excelPath = excelPath.Trim();
string filename = null;
try
{
filename = System.Configuration.ConfigurationSettings.AppSettings["filename"].ToString();
}
catch(Exception ex)
{
filename = null;
throw ex;
}
DataTable dt = new DataTable();
//DataSet ds = new DataSet();
if (string.IsNullOrEmpty(excelPath))
{
dt = null ;
//ds = null;
}
else
{
try
{
string strConn = @"Provider = Microsoft.ACE.OLEDB.12.0;Data Source=" + excelPath + ";Extended Properties = 'Excel 12.0;HDR=Yes;IMEX=1;'";
using(OleDbConnection oconn = new OleDbConnection(strConn))
{
OleDbCommand ocmd = null;
oconn.Open();
try
{
ocmd = new OleDbCommand("SELECT * FROM ["+filename+"$]", oconn);//在web.config中配置
OleDbDataAdapter oda = new OleDbDataAdapter(ocmd);
oda.Fill(dt);
}
catch(OleDbException oex)
{
dt = null;
throw oex;
//ds = null;
}
finally
{
oconn.Close();
ocmd.Dispose();
}
}
}
catch(Exception ex)
{
throw ex;
}
}
//return ds.Tables[0];
return dt;
}
说明:该方法需要一个参数用来获取Excel文件的路径,找到后放到一个DataTable中。 对于第二条,为了提高性能,我是这样实现的,每次遍历时只跟它后面的数据比较,因为它前面的数据已经跟它比较过了,没必要它再跟前面的数据比较 /// <summary>
/// 查看Excel文件中重复的数据
/// 该方法只是比较编号和客户名称,其他字段没有比较
/// </summary>
/// <param name="excelPath">string:Excel文件路径</param>
/// <returns>ArrayList:重复行组成的动态数组</returns>
public static ArrayList arrCFData(string excelPath)
{
ArrayList arrUserData = new ArrayList();
excelPath=excelPath.Trim();
if (string.IsNullOrEmpty(excelPath))
{
arrUserData = null;
}
else
{
string ret = null;
DataTable dtCompInfo = null;
try
{
dtCompInfo = DF.DBFactory.GetCompanyDAO().GetUserDataDTList(excelPath);
if(dtCompInfo!=null&&dtCompInfo.Rows.Count>0)
{
int count = dtCompInfo.Rows.Count;
int x, y;
for (int i = 0; i < count;i++ )
{
for (int j = i + 1; j < count; j++)
{
if (dtCompInfo.Rows[i][0].ToString().Equals(dtCompInfo.Rows[j][0].ToString()) && dtCompInfo.Rows[i][3].ToString().Equals(dtCompInfo.Rows[j][3].ToString()))
{
x = i + 2;
y = j + 2;
ret = string.Format("Excel数据中第{0}行和第{1}行数据重复",x, y);
arrUserData.Add(ret);
break;
}
}
//arrUserData.Add(dtCompInfo.Rows[i][0].ToString() + "出来吧" + dtCompInfo.Rows[i][3].ToString());
}
}
}
catch(Exception ex)
{
ExceptionManager.SaveException(ex, "Company.cs", ex.Message);
arrUserData = null;
}
finally
{
dtCompInfo = null;
}
}
return arrUserData;
}
说明:该算法的时间复杂度o(n)=n-1 + n-2 + n-3 +……+0=n *(n-1+0)/2 对于第3条:在查找Excel数据中重复行时,确实郁闷了一下午:明明两行数据一样,可就是检测不出来。后来请教了一个牛B同事,才发现原来是对Excel单元格格式不了解造成的。单元格都有默认格式,如果直接取单元格数据进行比较的话很容易出现错误。因为可能单元格的数据类型可能不一致,对于数字“1”在整型单元格中是“1”,但是在浮点类型中是“1.0”,如果直接比较就会认为不一致,所以用下面的方法将检查不出来:
if (dtCompInfo.Rows[i][0].Equals(dtCompInfo.Rows[j][0]) && dtCompInfo.Rows[i][3].Equals(dtCompInfo.Rows[j][3]))
{
x = i + 2;
y = j + 2;
ret = string.Format("Excel数据中第{0}行和第{1}行数据重复",x, y);
arrUserData.Add(ret);
break;
}
安全起见应该把获取的对象tostring()一下。 对于第四条:因为老板要知道excel数据中到底哪些行重复了,所以一旦找到后需要记录这两行的索引,我这读出来的数据跟excel数据实际对应的行数差两行,所以要在程序中读到的行索引基础上在加2。这时,由于对“i++”和++i“的用法不注意,有让我浪费了一个多小时时间:之前我的代码是这样: ……
if (dtCompInfo.Rows[i][0].ToString().Equals(dtCompInfo.Rows[j][0].ToString()) && dtCompInfo.Rows[i][3].ToString().Equals(dtCompInfo.Rows[j][3].ToString(
{
ret = string.Format("Excel数据中第{0}行和第{1}行数据重复",i+2, j+2);
arrUserData.Add(ret);
break;
} 说明:这样,执行完代码后还是差两行。想了一下原来是在把数据放到数据插到arrUserData(一个动态数组)之后才执行”i+2“和”j+2“,所以获取arrUserData中的值仍然比实际行数差2. 对于第五条:没啥好说的就是用事务来实现插入,一旦有异常回滚已经插入的数据,说实话,我是第一次使用事务,所以有必要总结一下 总结:手都酸了,洗澡睡觉,迎接明天的挑战