将C#嵌套对象保存到SQL server的有效方法

将C#嵌套对象保存到SQL server的有效方法,c#,sql-server,C#,Sql Server,我有一个表结构,它嵌套到5个级别,一对多关系向下。 我想知道将此类数据保存到SQL Server中的有效方法是什么。现在,我在每个子对象(C#)上循环,并运行一个insert,如果数据很大,它会变慢 在传统的ADO.NET中,有没有办法将C#直接传递给SQL?我有一个自定义框架,它为每个插入触发一个SQL脚本,从对象属性中提取值。我不能转移到EF或NHirbernate,因为这是一个现有的项目 我见过将C#对象插入数据表然后传递给SQl的方法,这是一种有效的方法吗 请告知。是,如果希望将数据集对

我有一个表结构,它嵌套到5个级别,一对多关系向下。 我想知道将此类数据保存到SQL Server中的有效方法是什么。现在,我在每个子对象(C#)上循环,并运行一个insert,如果数据很大,它会变慢

在传统的ADO.NET中,有没有办法将C#直接传递给SQL?我有一个自定义框架,它为每个插入触发一个SQL脚本,从对象属性中提取值。我不能转移到EF或NHirbernate,因为这是一个现有的项目

我见过将C#对象插入数据表然后传递给SQl的方法,这是一种有效的方法吗


请告知。

是,如果希望将数据集对象存储在数据库中,您可以选择以下选项 创建一个SQL UserDefinedType对象。
用所需的值填充对象,并读取存储过程中的值,用Temp中的值填充对象值,然后使用您的业务逻辑u可以存储在Db中。

我假设您从数据库的角度来看有类似的内容

CREATE TABLE Items (ID INT -- primary key, 
                    Name VARCHAR(MAX),
                    ParentID INT) -- foreign key that loops on the same table
在C中有这样一个对象#

为每个子项生成每个项的插入。如果你有很多孩子,这真的会减慢应用程序的速度

在本例中,我将使用(并且已经使用)一个自定义sql server类型和一个存储过程来在一次调用中保存整个过程

您需要创建与表匹配的类型:

CREATE TYPE dbo.ItemType AS TABLE
(
    ID INT,
    Name VARCHAR(MAX),
    ParentID INT
);
以及使用以下类型的简单过程:

CREATE PROCEDURE dbo.InsertItems
(
  @Items AS dbo.ItemType READONLY
)
AS
BEGIN
  INSERT INTO SampleTable(ID, Name, ParentID)
  SELECT ID, Name, ParentID From @Items
END
现在,从SQL Server端就可以做到这一点。现在转到C侧。你需要做两件事:

  • 将层次结构展平为列表
  • 将该列表作为数据表发送到数据库
  • 第一个可以使用类似(我使用,基本上是相同的东西)的东西来完成,使用一个简单的

    var items = root.Flatten(i => i.Children);
    
    要执行第二件事,首先需要将SQL Server类型声明为datatable:

    DataTable dt = new DataTable("Items"); 
    dt.Columns.Add("ID", typeof(int)); 
    dt.Columns.Add("Name", typeof(string)); 
    dt.Columns.Add("ParentID", typeof(int)); 
    
    接下来,只需填写以下值:

    foreach(var item in items)
    {
       dt.Rows.Add(item.ID, item.Name, item.ParentID);
    }
    
    并将它们附加到
    SqlParameter
    ,该参数应为
    SqlDbType.Structured
    类型,如下所示:

    using (var cmd = new SqlCommand("InsertItems", connection))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        var itemsParam = new SqlParameter("@Items", SqlDbType.Structured);
        itemsParam .Value = dt;
    
        cmd.Parameters.Add(itemsParam);
        cmd.ExecuteNonQuery();
    }
    

    而且,应该是这样。

    我仍然强烈推荐EntityFramework,尽管您说它不是一个理想的选择。您可以选中将对象序列化为xml并将xml传递给sql server的选项。在sql server中,您可以分别解析xml和insert。请查看sql server 2008及更高版本的表值参数-但您必须注意将层次结构扁平化为数据表。我同意@Maritim的观点,没有其他方法可以做到这一点,如果您要更改所有查询,工作负载类似于移动到EF。我不知道您是如何实现查询的,但一种有效的方法是将所有依赖查询包含在同一事务中,这将提高性能。即使您需要保存现有对象,也有一些方法可以使用Entity Framework来进行查询。若不可能,可以很容易地生成与数据库相关的对象,并将现有对象映射到EF对象。有趣的方法!并非适用于所有情况,但值得一试。在插入的情况下,这是否有效?比如说,如果层次结构是数据库的新层次结构?或者即使层次结构的一部分是新的?
    foreach(var item in items)
    {
       dt.Rows.Add(item.ID, item.Name, item.ParentID);
    }
    
    using (var cmd = new SqlCommand("InsertItems", connection))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        var itemsParam = new SqlParameter("@Items", SqlDbType.Structured);
        itemsParam .Value = dt;
    
        cmd.Parameters.Add(itemsParam);
        cmd.ExecuteNonQuery();
    }