[英]How to insert child category by specific parent category into table using ado.net?
I am trying to insert categories and subcategories from Excel into a database table. 我正在尝试将Excel中的类别和子类别插入数据库表中。
I have 1 Excel file which contains some data and from this Excel file I am creating dataset
which contains lots of datatables
. 我有一个包含一些数据,并从我创建这个Excel文件1个Excel文件dataset
,它含有许多的datatables
。
In this dataset
I have 2 datatables
in the form of this: 在这一dataset
我有2个datatables
中的这种形式:
Datatable 0 with records: Category 具有记录的数据表0: 类别
ParentCategory Description
Electronics jhdkhsd
Sports kjshfhs
Datatable 1 with records: SubCategory 具有记录的数据表1: SubCategory
Subcategory ParentCategory Description
Mobile Electronics weprwp
Tv Electronics sdflskd
Balls Sports kjshdfkjh
Shoes Sports uytuyt
Now my database tables are like this: 现在我的数据库表是这样的:
Category : Id,Name,Description,parentid
类别 : Id,Name,Description,parentid
So far I am successful inserting parent category but now trying to insert child categories but that is where currently i am struggling. 到目前为止,我已成功插入父类别,但现在尝试插入子类别,但这是我目前正在努力的地方。
This my code so far: 到目前为止,这是我的代码:
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);
}
}
Here in the last loop to insert child category; 这里在最后一个循环中插入子类别; I am confused about how to use same insertCommand
variable to insert child category? 我对如何使用相同的insertCommand
变量插入子类别感到困惑?
Update :I have used datatable Expression
to calculate parentid
like this: 更新 :我已经使用数据表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]);
}
Error : Computed column(parentid) cannot be inserted
. 错误 : Computed column(parentid) cannot be inserted
。
You are almost there with latest code. 您即将获得最新代码。
The only problem is that the calculated columns are not allowed to be used for inserting/updating the database table. 唯一的问题是,不允许将计算出的列用于插入/更新数据库表。 Btw, the error message is not " Computed column(parentid) cannot be inserted. ", but: 顺便说一句,错误消息不是“ 无法插入计算列(父代)。 ”,而是:
The column mapping from SourceColumn 'ParentId' failed because the DataColumn 'ParentId' is a computed column. SourceColumn'ParentId'的列映射失败,因为DataColumn'ParentId'是计算列。
I could agree that the message could have been better, and also I didn't find any documentation describing that. 我可以同意该信息可能会更好,而且我也没有找到任何描述此信息的文档。 Most probably the rationale is that the computed columns are not normally stored. 最有可能的理由是,通常不存储计算列。
Whatever the reason is, that's the reality. 无论原因是什么,这都是事实。 You have no other choice than creating a regular column and populating it with data manually. 除了创建常规列并手动填充数据外,您别无选择。
There are many ways to do that (both efficient and ineffient), but once you already created a relation, you can use the DataRow.GetParentRow
method to locate the related category record. 有很多方法可以做到这一点(有效和无效),但是一旦创建了关系,就可以使用DataRow.GetParentRow
方法来找到相关的类别记录。
With all that being said, replace the line 话虽如此,替换行
dsFinal.Tables[1].Columns.Add("ParentId", typeof(int),
"IIF(Parent.ParentCategory=ParentCategory,parent.Id,0)");
with the following snippet: 包含以下代码段:
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;
}
and you are done. 到此为止。
EDIT: Let me make it clear. 编辑:让我说清楚。 The only time critical operation here is locating the category id by name. 唯一关键的操作是按名称查找类别ID。 Using the relation and GetParentRow
is equivalent of the evaluating the expression accessing parent
as in your attempt. 与尝试使用关系和GetParentRow
等效于评估访问parent
的表达式。 Data relation internally maintains a lookup structure for supporting such operations. 数据关系在内部维护用于支持此类操作的查找结构。
If you want to get the best possible performance, then don't create a relation, but a dictionary. 如果要获得最佳性能,则不要创建关系,而要创建字典。 What you need is given a name (string), find the corresponding id (int), so Dictionary<string, int>
is a perfect candidate for that: 给您所需的名称(字符串),找到相应的ID(整数),因此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;
}
Change your relation so it's using Id and ParentId and your first solution will be working just right. 更改您的关系,使其使用Id和ParentId,并且您的第一个解决方案将正常工作。
When you will update that first table and the get the autoincremented value, it will automatically update the second table via the relation. 当您更新第一个表并获取自动递增的值时,它将通过该关系自动更新第二个表。 Here is an example. 这是一个例子。
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".
When using this method, i'll usually set my column to get a temporary "id" value by setting the column as an identity column with a seed and step set to -1. 当使用这种方法时,我通常将列设置为一个临时的“ id”值,方法是将该列设置为具有种子和步骤设置为-1的标识列。 This would go after the third line. 这将在第三行之后。
colParent.AutoIncrement = true;
colParent.AutoIncrementSeed = -1;
colParent.AutoIncrementStep = -1;
Unless you really need to have your relation on those string fields, there's no need to do any loop, computed column or anything overly complicated. 除非您真的需要在这些字符串字段上建立关系,否则不需要执行任何循环,计算列或任何过于复杂的操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.