如何使用 ado.net 将特定父类别的子类别插入到 table 中?
How to insert child category by specific parent category into table using ado.net?
我正在尝试将 Excel 中的类别和子类别插入数据库 table。
我有 1 个 Excel 文件,其中包含一些数据,我正在从这个 Excel 文件创建 dataset
,其中包含很多 datatables
.
在这个 dataset
中,我有 2 个 datatables
的形式:
数据table 0 条记录:类别
ParentCategory Description
Electronics jhdkhsd
Sports kjshfhs
数据table 1 条记录:子类别
Subcategory ParentCategory Description
Mobile Electronics weprwp
Tv Electronics sdflskd
Balls Sports kjshdfkjh
Shoes Sports uytuyt
现在我的数据库 table 是这样的:
类别:Id,Name,Description,parentid
到目前为止,我已成功插入父类别,但现在尝试插入子类别,但这是我目前正在努力的地方。
到目前为止,这是我的代码:
var dsFinal = new DataSet();
//Some code to read excel sheets and data from excel and create datatables and records with it.
dsControlSheet.Tables[0].Columns.Add("Id");
DataColumn parentId = new DataColumn("ParentId", typeof(int));
parentId.DefaultValue = 0;
dsFinal.Tables[0].Columns.Add(parentId);
dsFinal.Relations.Add("Abc",dsFinal.Tables[0].Columns["ParentCategory"],
dsFinal.Tables[1].Columns["ParentCategory"],false); //creating relation ship between Category datatable
// and SubCategory datatable on field ParentCategory
using (SqlConnection connection = new SqlConnection(""))
{
SqlDataAdapter adapter = new SqlDataAdapter();
var insertCommand = new SqlCommand("insert into Category (Name,Description) values (@ParentCategory,@Description) SET @Id = SCOPE_IDENTITY()", connection);
var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id");
insertCommand.Parameters.Add("@ParentCategory", SqlDbType.NVarChar, 50, "ParentCategory");
insertCommand.Parameters.Add("@Description", SqlDbType.NVarChar, 50, "Description");
parameter.Direction = ParameterDirection.Output;
insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
adapter.InsertCommand = insertCommand;
adapter.Update(dsFinal.Tables[0]); //successfully inserted parent category and got autoincremented value in Id column of my 0th datatable
//trying to insert child category using above insert command
foreach (DataRow parentCategory in dsFinal.Tables[0].Rows)
{
var child = parentCategory.GetChildRows("Abc").CopyToDataTable();//get child category of particular parent
adapter.Update(child);
}
}
这里在最后一个循环中插入子类别;我对如何使用感到困惑
使用相同的 insertCommand
变量来插入子类别?
更新:我用datatable Expression
这样计算parentid
:
using (SqlConnection connection = new SqlConnection(""))
{
SqlDataAdapter adapter = new SqlDataAdapter();
var insertCommand = new SqlCommand("insert into Category (Name,Description) values (@ParentCategory,@Description) SET @Id = SCOPE_IDENTITY()", connection);
var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id");
insertCommand.Parameters.Add("@ParentCategory", SqlDbType.NVarChar, 50, "ParentCategory");
insertCommand.Parameters.Add("@Description", SqlDbType.NVarChar, 50, "Description");
parameter.Direction = ParameterDirection.Output;
insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
adapter.InsertCommand = insertCommand;
adapter.Update(dsFinal.Tables[0]); //successfully inserted parent category and got autoincremented value in Id column of my 0th datatable
//For inserting child category..
//added column parentid to store child category
SqlDataAdapter da = new SqlDataAdapter();
dsFinal.Tables[1].Columns.Add("ParentId", typeof(int), "IIF(Parent.ParentCategory=ParentCategory,parent.Id,0)");
var insertChildCategoryCommand = new SqlCommand("insert into Category (Name,Description,ParentId) values (@Subcategory,@Description,@ParentId) SET @Id = SCOPE_IDENTITY()", connection);
var parameter1 = insertChildCategoryCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id");
insertChildCategoryCommand.Parameters.Add("@Subcategory", SqlDbType.NVarChar, 50, "Subcategory");
insertChildCategoryCommand.Parameters.Add("@Description", SqlDbType.NVarChar, 50, "Description");
insertChildCategoryCommand.Parameters.Add("@ParentId", SqlDbType.int, 0, "ParentId");
parameter1.Direction = ParameterDirection.Output;
insertChildCategoryCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
da.InsertCommand = insertChildCategoryCommand;
//Error here that computed column cannot be inserted.Here computed column is parentid
da.Update(dsFinal.Tables[1]);
}
错误:Computed column(parentid) cannot be inserted
.
你几乎已经有了最新的代码。
唯一的问题是计算列不允许用于 inserting/updating 数据库 table。顺便说一句,错误消息不是“无法插入计算列(parentid)。”,而是:
The column mapping from SourceColumn 'ParentId' failed because the DataColumn 'ParentId' is a computed column.
我同意该消息本来可以更好,而且我也没有找到任何描述该消息的文档。最有可能的原因是计算列没有正常存储。
不管是什么原因,这就是现实。您别无选择,只能创建常规列并手动填充数据。
有很多方法可以做到这一点(有效率的和低效率的),但是一旦你已经创建了一个关系,你可以使用 DataRow.GetParentRow
方法来定位相关的类别记录。
综上所述,替换行
dsFinal.Tables[1].Columns.Add("ParentId", typeof(int),
"IIF(Parent.ParentCategory=ParentCategory,parent.Id,0)");
使用以下代码段:
var dtSubCategory = dsFinal.Tables[1];
dtSubCategory.Columns.Add("ParentId", typeof(int));
foreach (var drSubCategory in dtSubCategory.AsEnumerable())
{
var drCategory = drSubCategory.GetParentRow("Abc");
drSubCategory["ParentId"] = drCategory != null ? drCategory["Id"] : 0;
}
大功告成。
编辑: 让我说清楚。这里唯一时间紧迫的操作是 locating 按名称分类 id。使用关系和 GetParentRow
等同于评估访问 parent
的表达式,就像您尝试的那样。数据关系在内部维护一个查找结构以支持此类操作。
如果你想获得最好的性能,那么不要创建关系,而是创建字典。你需要的是给定一个名称(字符串),找到相应的 id(int),所以 Dictionary<string, int>
是一个完美的候选者:
var categoryIds = dsFinal.Tables[0].AsEnumerable().ToDictionary(
dr => dr.Field<string>("ParentCategory"), // key
dr => dr.Field<int>("Id") // value
);
var dtSubCategory = dsFinal.Tables[1];
dtSubCategory.Columns.Add("ParentId", typeof(int));
foreach (var drSubCategory in dtSubCategory.AsEnumerable())
{
int categoryId;
categoryIds.TryGetValue(drSubCategory.Field<string>("ParentCategory"), out categoryId);
drSubCategory["ParentId"] = categoryId;
}
更改您的关系,使其使用 Id 和 ParentId,您的第一个解决方案将正常工作。
当您更新第一个 table 并获取自动增量值时,它将通过关系自动更新第二个 table。这是一个例子。
DataSet ds = new DataSet();
DataTable dt = new DataTable();
var colParent = dt.Columns.Add("id", typeof(int));
DataTable dtChild = new DataTable();
var colChild = dtChild.Columns.Add("parentid", typeof(int));
ds.Tables.Add(dt);
ds.Tables.Add(dtChild);
ds.Relations.Add("relation1", colParent, colChild);
DataRow rowParent = dt.NewRow();
rowParent["id"] = 1;
dt.Rows.Add(rowParent);
DataRow rowChild = dtChild.NewRow();
rowChild["parentid"] = rowParent["id"];
dtChild.Rows.Add(rowChild);
// at this point, parentid from rowChild is "1".
rowParent["id"] = 10; // DataAdapter.Update simulation.
// and now parentid from rowChild has been update via the relation to "10".
使用此方法时,我通常会通过将列设置为标识列并将种子和步长设置为 -1 来将我的列设置为获得临时 "id" 值。这将在第三行之后。
colParent.AutoIncrement = true;
colParent.AutoIncrementSeed = -1;
colParent.AutoIncrementStep = -1;
除非您真的需要在这些字符串字段上建立关系,否则无需执行任何循环、计算列或任何过于复杂的操作。
我正在尝试将 Excel 中的类别和子类别插入数据库 table。
我有 1 个 Excel 文件,其中包含一些数据,我正在从这个 Excel 文件创建 dataset
,其中包含很多 datatables
.
在这个 dataset
中,我有 2 个 datatables
的形式:
数据table 0 条记录:类别
ParentCategory Description
Electronics jhdkhsd
Sports kjshfhs
数据table 1 条记录:子类别
Subcategory ParentCategory Description
Mobile Electronics weprwp
Tv Electronics sdflskd
Balls Sports kjshdfkjh
Shoes Sports uytuyt
现在我的数据库 table 是这样的:
类别:Id,Name,Description,parentid
到目前为止,我已成功插入父类别,但现在尝试插入子类别,但这是我目前正在努力的地方。
到目前为止,这是我的代码:
var dsFinal = new DataSet();
//Some code to read excel sheets and data from excel and create datatables and records with it.
dsControlSheet.Tables[0].Columns.Add("Id");
DataColumn parentId = new DataColumn("ParentId", typeof(int));
parentId.DefaultValue = 0;
dsFinal.Tables[0].Columns.Add(parentId);
dsFinal.Relations.Add("Abc",dsFinal.Tables[0].Columns["ParentCategory"],
dsFinal.Tables[1].Columns["ParentCategory"],false); //creating relation ship between Category datatable
// and SubCategory datatable on field ParentCategory
using (SqlConnection connection = new SqlConnection(""))
{
SqlDataAdapter adapter = new SqlDataAdapter();
var insertCommand = new SqlCommand("insert into Category (Name,Description) values (@ParentCategory,@Description) SET @Id = SCOPE_IDENTITY()", connection);
var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id");
insertCommand.Parameters.Add("@ParentCategory", SqlDbType.NVarChar, 50, "ParentCategory");
insertCommand.Parameters.Add("@Description", SqlDbType.NVarChar, 50, "Description");
parameter.Direction = ParameterDirection.Output;
insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
adapter.InsertCommand = insertCommand;
adapter.Update(dsFinal.Tables[0]); //successfully inserted parent category and got autoincremented value in Id column of my 0th datatable
//trying to insert child category using above insert command
foreach (DataRow parentCategory in dsFinal.Tables[0].Rows)
{
var child = parentCategory.GetChildRows("Abc").CopyToDataTable();//get child category of particular parent
adapter.Update(child);
}
}
这里在最后一个循环中插入子类别;我对如何使用感到困惑
使用相同的 insertCommand
变量来插入子类别?
更新:我用datatable Expression
这样计算parentid
:
using (SqlConnection connection = new SqlConnection(""))
{
SqlDataAdapter adapter = new SqlDataAdapter();
var insertCommand = new SqlCommand("insert into Category (Name,Description) values (@ParentCategory,@Description) SET @Id = SCOPE_IDENTITY()", connection);
var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id");
insertCommand.Parameters.Add("@ParentCategory", SqlDbType.NVarChar, 50, "ParentCategory");
insertCommand.Parameters.Add("@Description", SqlDbType.NVarChar, 50, "Description");
parameter.Direction = ParameterDirection.Output;
insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
adapter.InsertCommand = insertCommand;
adapter.Update(dsFinal.Tables[0]); //successfully inserted parent category and got autoincremented value in Id column of my 0th datatable
//For inserting child category..
//added column parentid to store child category
SqlDataAdapter da = new SqlDataAdapter();
dsFinal.Tables[1].Columns.Add("ParentId", typeof(int), "IIF(Parent.ParentCategory=ParentCategory,parent.Id,0)");
var insertChildCategoryCommand = new SqlCommand("insert into Category (Name,Description,ParentId) values (@Subcategory,@Description,@ParentId) SET @Id = SCOPE_IDENTITY()", connection);
var parameter1 = insertChildCategoryCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id");
insertChildCategoryCommand.Parameters.Add("@Subcategory", SqlDbType.NVarChar, 50, "Subcategory");
insertChildCategoryCommand.Parameters.Add("@Description", SqlDbType.NVarChar, 50, "Description");
insertChildCategoryCommand.Parameters.Add("@ParentId", SqlDbType.int, 0, "ParentId");
parameter1.Direction = ParameterDirection.Output;
insertChildCategoryCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
da.InsertCommand = insertChildCategoryCommand;
//Error here that computed column cannot be inserted.Here computed column is parentid
da.Update(dsFinal.Tables[1]);
}
错误:Computed column(parentid) cannot be inserted
.
你几乎已经有了最新的代码。
唯一的问题是计算列不允许用于 inserting/updating 数据库 table。顺便说一句,错误消息不是“无法插入计算列(parentid)。”,而是:
The column mapping from SourceColumn 'ParentId' failed because the DataColumn 'ParentId' is a computed column.
我同意该消息本来可以更好,而且我也没有找到任何描述该消息的文档。最有可能的原因是计算列没有正常存储。
不管是什么原因,这就是现实。您别无选择,只能创建常规列并手动填充数据。
有很多方法可以做到这一点(有效率的和低效率的),但是一旦你已经创建了一个关系,你可以使用 DataRow.GetParentRow
方法来定位相关的类别记录。
综上所述,替换行
dsFinal.Tables[1].Columns.Add("ParentId", typeof(int),
"IIF(Parent.ParentCategory=ParentCategory,parent.Id,0)");
使用以下代码段:
var dtSubCategory = dsFinal.Tables[1];
dtSubCategory.Columns.Add("ParentId", typeof(int));
foreach (var drSubCategory in dtSubCategory.AsEnumerable())
{
var drCategory = drSubCategory.GetParentRow("Abc");
drSubCategory["ParentId"] = drCategory != null ? drCategory["Id"] : 0;
}
大功告成。
编辑: 让我说清楚。这里唯一时间紧迫的操作是 locating 按名称分类 id。使用关系和 GetParentRow
等同于评估访问 parent
的表达式,就像您尝试的那样。数据关系在内部维护一个查找结构以支持此类操作。
如果你想获得最好的性能,那么不要创建关系,而是创建字典。你需要的是给定一个名称(字符串),找到相应的 id(int),所以 Dictionary<string, int>
是一个完美的候选者:
var categoryIds = dsFinal.Tables[0].AsEnumerable().ToDictionary(
dr => dr.Field<string>("ParentCategory"), // key
dr => dr.Field<int>("Id") // value
);
var dtSubCategory = dsFinal.Tables[1];
dtSubCategory.Columns.Add("ParentId", typeof(int));
foreach (var drSubCategory in dtSubCategory.AsEnumerable())
{
int categoryId;
categoryIds.TryGetValue(drSubCategory.Field<string>("ParentCategory"), out categoryId);
drSubCategory["ParentId"] = categoryId;
}
更改您的关系,使其使用 Id 和 ParentId,您的第一个解决方案将正常工作。
当您更新第一个 table 并获取自动增量值时,它将通过关系自动更新第二个 table。这是一个例子。
DataSet ds = new DataSet();
DataTable dt = new DataTable();
var colParent = dt.Columns.Add("id", typeof(int));
DataTable dtChild = new DataTable();
var colChild = dtChild.Columns.Add("parentid", typeof(int));
ds.Tables.Add(dt);
ds.Tables.Add(dtChild);
ds.Relations.Add("relation1", colParent, colChild);
DataRow rowParent = dt.NewRow();
rowParent["id"] = 1;
dt.Rows.Add(rowParent);
DataRow rowChild = dtChild.NewRow();
rowChild["parentid"] = rowParent["id"];
dtChild.Rows.Add(rowChild);
// at this point, parentid from rowChild is "1".
rowParent["id"] = 10; // DataAdapter.Update simulation.
// and now parentid from rowChild has been update via the relation to "10".
使用此方法时,我通常会通过将列设置为标识列并将种子和步长设置为 -1 来将我的列设置为获得临时 "id" 值。这将在第三行之后。
colParent.AutoIncrement = true;
colParent.AutoIncrementSeed = -1;
colParent.AutoIncrementStep = -1;
除非您真的需要在这些字符串字段上建立关系,否则无需执行任何循环、计算列或任何过于复杂的操作。