使用 C#、EF 和 SQL 服务器从 Excel 文件仅插入不存在的行到数据库中
Insert into database from an Excel file only rows that don't exist, using C#, EF, and SQL Server
我读取了一个 Excel 文件并将该数据插入数据库 table,但每次我这样做时,它都会添加现有行和新数据,我只想插入table 中尚不存在的行,我的唯一 ID 是当前时间戳。
例如,这是我第一次插入时当前发生的情况:
ExcelFile Database Table
a | b | date a | b | date
----------- ---------------
1 | 1 | 2018/02/12 1 | 1 | 2018/02/12
2 | 2 | 2018 /03/12 2 | 2 | 2018 /03/12
当我进行第二次插入时会发生这种情况:
ExcelFile Database Table
a | b | date a | b | date
----------- ---------------
1 | 1 | 2018/02/12 1 | 1 | 2018/02/12
2 | 2 | 2018 /03/12 2 | 2 | 2018 /03/12
3 | 3 | 2018 /04/12 1 | 1 | 2018/02/12
2 | 2 | 2018 /03/12
3 | 3 | 2018 /04/12
我使用 Entity Framework 来执行这个和 ExcelDataReader
包:
var result = reader.AsDataSet();
DataTable dt = new DataTable();
dt = result.Tables[0]; // here I store the data from the Excel file
foreach (DataRow row in dt.Rows)
{
using (AppContext context = new AppContext())
{
Data data = new Data();
string date = row.ItemArray[4].ToString();
DateTime parseDate = DateTime.Parse(date);
Data datos = new Data
{
a = row.ItemArray[0].ToString(),
b = row.ItemArray[1].ToString(),
c = row.ItemArray[2].ToString(),
d = row.ItemArray[3].ToString(),
e = parseDate
};
context.Data.Add(datos);
context.SaveChanges();
}
}
有没有办法过滤 excel 文件或比较它们?
我洗耳恭听
在添加之前检查现有行。应在计算 parseDate
.
的下方插入以下内容
var existingRow = context.Data.FirstOrDefault(d=>d.e == parseDate); //Note that the ".e" should refer to your "date" field
if (existingRow != null)
{
//This row already exists
}
else
{
//It doesn't exist, go ahead and add it
}
如果 "a" 是 table 上的 PK 并且跨行唯一,那么我会在插入之前通过 ID 检查现有行的存在。与迈克的回应类似,尽管一个考虑因素是 table 是否有多个列我会避免返回实体,而只是使用 .Any()
进行存在检查
if (!context.Data.Any(x => x.a == row.a)
// insert the row as a new entity
这里需要注意的是,如果 excel 文件包含编辑、数据更改的现有行,则此文件将不适用。
对于批量导入流程,我通常会首先将 excel 数据暂存到暂存 table 中来处理这些流程。 (在每次导入之前清除暂存 table)从那里我会将实体映射到暂存 table,而实体则映射到 "real" table。如果有一个 "modified date" 可以从文件中为每条记录提取,那么我也会将导入 date/time 作为应用程序的一部分存储,以便在选择要从暂存中导入的行时 table,仅获取修改 date/time > 最后导入 date/time 的记录。从那里您可以批量查询暂存 table 中的数据,并查找新记录与现有修改。我发现在迁移的两边查询实体比处理导入的内存块更灵活。对于小的导入可能不值得,但对于较大的文件,您需要使用较小的子集和过滤,它可以使事情变得更容易。
在@MikeH 的帮助下,我可以准确地执行我需要的操作
这样,只添加了具有不同 DateTime 的行(在我的例子中,DateTime 始终是升序值。)
foreach (DataRow row in dt.Rows) // dt = my dataTable loaded with ExcelDataReader
{
using (AppContext context = new AppContext())
{
string date = row.ItemArray[4].ToString();
DateTime parseDate = DateTime.Parse(date); // I did a parse because the column "e" only accepted DateTime and not String types.
var existingRow = context.Data.FirstOrDefault(d => d.e == parseDate);
if (existingRow != null)
{
Console.WriteLine("Do Nothing");
}
else
{
Data datos = new Data
{
a = row.ItemArray[0].ToString(),
b = row.ItemArray[1].ToString(),
c = row.ItemArray[2].ToString(),
d = row.ItemArray[3].ToString(),
e = parseDate
};
context.Data.Add(datos);
context.SaveChanges();
}
}
}
我读取了一个 Excel 文件并将该数据插入数据库 table,但每次我这样做时,它都会添加现有行和新数据,我只想插入table 中尚不存在的行,我的唯一 ID 是当前时间戳。
例如,这是我第一次插入时当前发生的情况:
ExcelFile Database Table
a | b | date a | b | date
----------- ---------------
1 | 1 | 2018/02/12 1 | 1 | 2018/02/12
2 | 2 | 2018 /03/12 2 | 2 | 2018 /03/12
当我进行第二次插入时会发生这种情况:
ExcelFile Database Table
a | b | date a | b | date
----------- ---------------
1 | 1 | 2018/02/12 1 | 1 | 2018/02/12
2 | 2 | 2018 /03/12 2 | 2 | 2018 /03/12
3 | 3 | 2018 /04/12 1 | 1 | 2018/02/12
2 | 2 | 2018 /03/12
3 | 3 | 2018 /04/12
我使用 Entity Framework 来执行这个和 ExcelDataReader
包:
var result = reader.AsDataSet();
DataTable dt = new DataTable();
dt = result.Tables[0]; // here I store the data from the Excel file
foreach (DataRow row in dt.Rows)
{
using (AppContext context = new AppContext())
{
Data data = new Data();
string date = row.ItemArray[4].ToString();
DateTime parseDate = DateTime.Parse(date);
Data datos = new Data
{
a = row.ItemArray[0].ToString(),
b = row.ItemArray[1].ToString(),
c = row.ItemArray[2].ToString(),
d = row.ItemArray[3].ToString(),
e = parseDate
};
context.Data.Add(datos);
context.SaveChanges();
}
}
有没有办法过滤 excel 文件或比较它们?
我洗耳恭听
在添加之前检查现有行。应在计算 parseDate
.
var existingRow = context.Data.FirstOrDefault(d=>d.e == parseDate); //Note that the ".e" should refer to your "date" field
if (existingRow != null)
{
//This row already exists
}
else
{
//It doesn't exist, go ahead and add it
}
如果 "a" 是 table 上的 PK 并且跨行唯一,那么我会在插入之前通过 ID 检查现有行的存在。与迈克的回应类似,尽管一个考虑因素是 table 是否有多个列我会避免返回实体,而只是使用 .Any()
if (!context.Data.Any(x => x.a == row.a)
// insert the row as a new entity
这里需要注意的是,如果 excel 文件包含编辑、数据更改的现有行,则此文件将不适用。
对于批量导入流程,我通常会首先将 excel 数据暂存到暂存 table 中来处理这些流程。 (在每次导入之前清除暂存 table)从那里我会将实体映射到暂存 table,而实体则映射到 "real" table。如果有一个 "modified date" 可以从文件中为每条记录提取,那么我也会将导入 date/time 作为应用程序的一部分存储,以便在选择要从暂存中导入的行时 table,仅获取修改 date/time > 最后导入 date/time 的记录。从那里您可以批量查询暂存 table 中的数据,并查找新记录与现有修改。我发现在迁移的两边查询实体比处理导入的内存块更灵活。对于小的导入可能不值得,但对于较大的文件,您需要使用较小的子集和过滤,它可以使事情变得更容易。
在@MikeH 的帮助下,我可以准确地执行我需要的操作 这样,只添加了具有不同 DateTime 的行(在我的例子中,DateTime 始终是升序值。)
foreach (DataRow row in dt.Rows) // dt = my dataTable loaded with ExcelDataReader
{
using (AppContext context = new AppContext())
{
string date = row.ItemArray[4].ToString();
DateTime parseDate = DateTime.Parse(date); // I did a parse because the column "e" only accepted DateTime and not String types.
var existingRow = context.Data.FirstOrDefault(d => d.e == parseDate);
if (existingRow != null)
{
Console.WriteLine("Do Nothing");
}
else
{
Data datos = new Data
{
a = row.ItemArray[0].ToString(),
b = row.ItemArray[1].ToString(),
c = row.ItemArray[2].ToString(),
d = row.ItemArray[3].ToString(),
e = parseDate
};
context.Data.Add(datos);
context.SaveChanges();
}
}
}