0

私は以下を持っています、私はそれを私が望むように動かすことができました、しかし私はそれを間違った方法でやっていると思います、これがより効率的な方法でどのように行われることができるか説明できますか?また、同じメソッド内での場合とCategories同じようにループして実行します。DistrictsInsert()

前もって感謝します。

    #region Methods
    public int Insert(List<District> Districts, List<Category> Categories)
    {
        StringBuilder sqlString = new StringBuilder("INSERT INTO Stores (name, image) VALUES (@Name, @Image);");

        using (SqlConnection sqlConnection = new
           SqlConnection(ConfigurationManager.ConnectionStrings["OahuDB"].ConnectionString))
        {
            SqlCommand sqlCommand = new SqlCommand(sqlString.ToString(), sqlConnection);
            sqlCommand.Parameters.AddWithValue("@Name", this.Name);
            sqlCommand.Parameters.AddWithValue("@Image", this.Image);

            sqlConnection.Open();
            int x = (int)sqlCommand.ExecuteScalar();

            sqlString.Clear();
            sqlCommand.Parameters.Clear();

            foreach (District item in Districts)
            {
                sqlString.AppendLine("INSERT INTO districts_has_stores (district_id, store_id) VALUES (@DistrictID, @StoreID);");
                sqlCommand.CommandText = sqlString.ToString();
                sqlCommand.Parameters.AddWithValue("@DistrictID", item.ID);
                sqlCommand.ExecuteNonQuery();
            }

            return x;
        }
    }

編集

次のようにして上記を達成するのは間違っていますか?

            sqlString.Clear();
            sqlCommand.Parameters.Clear();
            sqlString.AppendLine("INSERT INTO districts_has_stores (district_id, store_id) VALUES (@DistrictID, @StoreID);");
            sqlCommand.CommandText = sqlString.ToString();
            sqlCommand.Parameters.AddWithValue("@StoreID", x);
            foreach (District item in Districts)
            {
                sqlCommand.Parameters.AddWithValue("@DistrictID", item.ID);
                sqlCommand.ExecuteNonQuery();
            } 
            sqlString.Clear();
            sqlCommand.Parameters.Clear();
            sqlString.AppendLine("INSERT INTO categories_has_stores (category_id, store_id) VALUES (@CategoryID, @StoreID);");
            sqlCommand.CommandText = sqlString.ToString();
            sqlCommand.Parameters.AddWithValue("@StoreID", x);
            foreach (Category item in Categories)
            {
                sqlCommand.Parameters.AddWithValue("@CategoryID", item.ID);
                sqlCommand.ExecuteNonQuery();
            } 
4

5 に答える 5

4

最初の明らかなことは、sqlCommandの不変部分をループの外に移動することです

sqlCommand.Parameters.Clear(); 
sqlString.Clear();
sqlString.AppendLine("INSERT INTO districts_has_stores (district_id, store_id) VALUES (@DistrictID, @StoreID);"); 
sqlCommand.CommandText = sqlString.ToString(); 
sqlCommand.Parameters.AddWithValue("@DistrictID", 0);  // as dummy value
sqlCommand.Parameters.AddWithValue("@StoreID", x);  // invariant
foreach (District item in Districts) 
{ 
    sqlCommand.Parameters["@DistrictID"].Value = item.ID; 
    sqlCommand.ExecuteNonQuery(); 
} 

しかし、これはあなたの根本的な問題に答えるものではありません。データベースに何度もアクセスしないようにする方法。
このように複数の挿入を使用してクエリを作成できます

sqlString.Clear();
sqlString.Append("INSERT INTO districts_has_stores (district_id, store_id) VALUES (");
foreach(District item in Districts)
{
    sqlString.Append(item.ID.ToString);
    sqlString.Append(", ")
    sqlString.Append(x.ToString()); 
    sqlString.Append("),"); 
}
sqlString.Length--;
sqlCommand.CommandText = sqlString.ToString()

しかし、文字列の連結は本当に悪い習慣であり、私はこの解決策を単なる例として提示し、この種のアプローチを提案したくありません。

最後の可能性は、テーブル値パラメーター(SqlServer 2008からのみ)です。

まず、渡すテーブルのSQLタイプを作成する必要があります

CREATE TYPE dbo.DistrictsType AS TABLE
    ( DistrictID int, StoreID int )

渡されたデータテーブルからデータを挿入するStoredProcedure

CREATE PROCEDURE usp_InsertDistricts 
(@tvpNewDistricts dbo.DistrictsType READONLY)
AS
BEGIN
    INSERT INTO dbo.Districts (DistrictID, StoreID)
    SELECT dt.DistrictID, dt.StoreID FROM @tvpNewDistricts AS dt;
END

次に、コードに戻って、地区をストアドプロシージャに渡します

(おそらく、DataTableのリストを変換する必要があります)

DataTable dtDistricts = ConvertListToDataTable(Districts);
SqlCommand insertCommand = new SqlCommand("usp_InsertDistricts", sqlConnection);
SqlParameter p1 = insertCommand.Parameters.AddWithValue("@tvpNewDistricts", dtDistricts);
p1.SqlDbType = SqlDbType.Structured;
p1.TypeName = "dbo.DistrictsType";
insertCommand.ExecuteNonQuery();

上記のリンクを振り返ると、データベースのバックエンドに1つのステップでデータを渡す他の方法が見つかります。...(最後までスクロールすると、を必要としないメソッドも見つかります。データベースのストアドプロシージャ)

于 2012-07-07T16:03:26.513 に答える
2

ストアにID列があると仮定すると、SQL Serverで、それを利用するためにテーブルタイプとテーブル値パラメーターを作成します。

CREATE TYPE dbo.DistrictsTVP AS TABLE
(
  DistrictID INT -- PRIMARY KEY? I hope so.
);
GO

CREATE PROCEDURE dbo.InsertStoreAndDistricts
  @Name NVARCHAR(255),
  @Image <some data type???>,
  @Districts dbo.DistrictsTVP READONLY
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @StoreID INT;

  INSERT dbo.Stores(name, [image]) SELECT @Name, @Image;

  SET @StoreID = SCOPE_IDENTITY();

  INSERT dbo.district_has_stores(district_id, store_id)
    SELECT DistrictID, @StoreID
      FROM @Districts;
END
GO

次に、C#では、ループせずにリストを直接渡すことができます。

  using (...)
  {
    SqlCommand cmd       = new SqlCommand("dbo.InsertStoreAndDistricts", sqlConnection);
    cmd.CommandType      = CommandType.StoredProcedure;
    SqlParameter tvparam = cmd.Parameters.AddWithValue("@Districts", Districts);
    tvparam.SqlDbType    = SqlDbType.Structured;

    // other params here - name and image

    cmd.ExecuteNonQuery();
  }
于 2012-07-07T16:13:08.593 に答える
1

最近、私のプロジェクトでは、ストアドプロシージャのデータ型としてXMLを使用し、データベースに何度もアクセスする代わりに、更新と削除を1回のショットで挿入しました。

サンプルストアドプロシージャ

ALTER PROCEDURE [dbo].[insertStore]
@XMLDATA xml,
@name varchar(50),
@image datatype
 AS
 Begin
  INSERT INTO Store
  (name
   ,image
  )
Select XMLDATA.item.value('@name[1]', 'varchar(10)') AS Name,   
XMLDATA.item.value('@image[1]', 'yourData type') AS Image
FROM @XMLDATA.nodes('//Stores/InsertList/Store') AS XMLDATA(item)
END

同様に、更新と削除のために書き込むことができます。C#では、xmlを作成する必要があります

public  string GenerateXML(List<District> Districts)
 var xml = new StringBuilder();
 var insertxml = new StringBuilder();
 xml.Append("<Stores>");
 for (var i = 0; i < Districts.Count; i++)
        { var obj = Districts[i];
          insertxml.Append("<Store");
          insertxml.Append(" Name=\"" + obj.Name  + "\" ");
          insertxml.Append(" Image=\"" + obj.Image + "\" ");
          insertxml.Append(" />");
        }
xml.Append("<InsertList>");
xml.Append(insertxml.ToString());
xml.Append("</InsertList>");

SqlCommand cmd= new SqlCommand("insertStore",connectionString);
cmd.CommandType=CommandType.StoredProcedure;
SqlParameter param = new SqlParameter ();
param.ParameterName ="@XMLData";
param.value=xml;
paramter.Add(param);
cmd.ExecuteNonQuery();
于 2012-07-07T16:33:13.477 に答える
0

個人的には、挿入用のストアドプロシージャを作成し、テーブル値パラメーターを渡します。これにより、次のことが可能になります。

INSERT tbl (f1, f2, ... fN)
SELECT * FROM @TVP

http://msdn.microsoft.com/en-us/library/bb510489.aspx

SQL 2005を使用している場合を除き、ストアドプロシージャでXMLパラメータを使用し、挿入するコレクションをシリアル化します。

于 2012-07-07T16:11:27.097 に答える
0

システム設計について考えてください。挿入する必要のあるデータはどこから来ていますか?すでにデータベース、別のデータベース、または他の種類のデータストアにある場合は、ストアドプロシージャのループで、あるデータベースから別のデータベースに挿入するだけで、より大量の転送を実行できるはずです。

データがユーザーからのものである場合、またはサードパーティプログラムからのエクスポートなど、互換性のないデータストアからのものである場合、基本的に、データをデータベースに取り込むには、データベースへのラウンドトリップがかなり必要になることを理解する必要があります。一部のテーブルやXMLなどを使用できますが、実際には、他の方法を使用して一括挿入を行うのに近いものです。

要するに、SQLデータベースは一度に1つずつ挿入を行うように設計されているということです。UIを使用しているユーザーに一度に何千もの入力を要求することはないため、これは99%の確率で問題ありません。

于 2012-07-07T18:23:38.453 に答える