简体   繁体   English

如何使用ado.net将特定父类别的子类别插入表中?

[英]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.

相关问题 ADO.NET-使用Adapter.Update()插入父表中的列的子集 - ADO.NET - Insert using Adapter.Update() with a subset of columns from Parent Table 如何使用Ado.net C#插入项目列表? - How to insert list of items Using Ado.net C#? 使用 ADO.NET 如何将数据列表插入 SQL? - Using ADO.NET how to insert list of data into SQL? 如何使用ADO.NET更新大表 - How to update a large table using ADO.NET Linq to ADO.NET父/子查询帮助 - Linq to ADO.NET parent/child query help 如果子表包含C#/ ADO.NET 2.0中父表中没有父行的行,是否可以将DataRelation添加到DataSet - is it possible to add DataRelation to DataSet if child table contains rows that have no parent in parent table in C# / ADO.NET 2.0 ADO.net如何使用C#和连接的模型在页面加载时将特定数据库表单元格中的数据绑定到转发器控件上? - ADO.net how to bind data from specific database table cell to a repeater control on page load using C# & the connected model? 使用INSERT_IDENTITY插入多个表-ADO.Net - Insert into multiple tables using INSERT_IDENTITY - ADO.Net 使用带有域服务的ado.net实体框架更新父表 - Update on Parent Table with ado.net entity framework with domain services 使用ADO.net从MS Access数据库读取内容,并尝试将值插入SQL Server表中 - Reading content from MS Access db using ADO.net and trying to insert the values into a SQL Server table
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM