Pertanyaan Apakah boleh lewat SQLCommand sebagai parameter?


Saya memiliki Layer Bisnis yang melewati string Conn dan SQLCommand ke Layer Data seperti itu

    public void PopulateLocalData()
    {
       System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
       cmd.CommandType = System.Data.CommandType.StoredProcedure;
       cmd.CommandText = "usp_PopulateServiceSurveyLocal";
       DataLayer.DataProvider.ExecSQL(ConnString, cmd);
    }

The DataLayer kemudian hanya mengeksekusi sql seperti itu

        public static int ExecSQL(string sqlConnString, System.Data.SqlClient.SqlCommand cmd)
    { 
        int rowsAffected;
        using (SqlConnection conn = new SqlConnection(sqlConnString))
        {
            conn.Open();
            cmd.Connection = conn;
            rowsAffected = cmd.ExecuteNonQuery();
            cmd.Dispose();
        }
        return rowsAffected;
    }

Apakah tidak apa-apa bagi saya untuk menyampaikan SQLCommand sebagai parameter seperti ini atau apakah ada cara yang lebih baik yang lebih dapat diterima untuk melakukannya. Salah satu kekhawatiran saya adalah jika kesalahan terjadi saat mengeksekusi query, baris cmd.disposisi tidak akan pernah dieksekusi. Apakah itu berarti akan terus menggunakan memori yang tidak akan pernah dirilis?

Memperbarui:

Mengikuti saran Eric, saya secara lebih eksplisit membagi Lapisan Bisnis dan Data sehingga metode dalam Lapisan Bisnis terlihat seperti ini

    public void PopulateLocalData()
    {
        DataLayer Data = new DataLayer(this.ConnString);
        Data.UpdateLocalData();
    }

dan metode yang disebut dalam DataLayer terlihat seperti ini.

        public void UpdateLocalData()
    {
        using (SqlConnection conn = new SqlConnection(this.ConnString))
        using(SqlCommand cmd = new SqlCommand())
        {
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.CommandText = "usp_PopulateServiceSurveyLocal";
            conn.Open();
            cmd.Connection = conn;
            cmd.ExecuteNonQuery();
        }
    }

Dengan cara ini sangat jelas bahwa SQLCommand dan SQLConnection akan dibuang dengan benar. Terima kasih.


8
2018-04-23 13:49


asal


Jawaban:


Idealnya, lapisan bisnis Anda tidak harus menyadari rincian penerapan lapisan data Anda. Jadi, apakah Anda mengimplementasikan lapisan data dengan SqlCommand objek atau dengan sesuatu seperti NHibernate, seharusnya tidak relevan dengan lapisan bisnis. Ini membuatnya secara teoritis berbicara mudah untuk 'menggeser' lapisan data Anda dan menggantinya dengan yang lain.

Meringkas: melewati SqlCommand dari lapisan bisnis ke lapisan data di mata saya tidak dianggap praktik yang baik.

Mengenai Dispose(): jika Anda menggunakan pernyataan menggunakan (seperti using(SqlConnection ...)), yang Dispose() metode dipanggil secara otomatis di akhir pernyataan penggunaan. Anda tidak harus melakukan ini secara manual.


6
2018-04-23 13:59



Mengapa Anda tidak mengubahnya ke ini:

public static int ExecProcedure(string sqlConnString, string procedureName)
{
    using (var cmd = new System.Data.SqlClient.SqlCommand())
    {
        cmd.CommandType = System.Data.CommandType.StoredProcedure;
        cmd.CommandText = procedureName;
        int rowsAffected;
        using (SqlConnection conn = new SqlConnection(sqlConnString))
        {
            conn.Open();
            cmd.Connection = conn;
            return cmd.ExecuteNonQuery();
        }
    }
}

Apakah Anda ingin parameter tambahan? Buat overload, refactor. Bagikan kode paling banyak dalam fungsi umum. Menciptakan new System.Data.SqlClient.SqlCommand() di mana-mana adalah pendekatan yang salah.


0
2018-04-23 13:58



Yang menciptakan Komando harus bertanggung jawab untuk membuangnya. Cara termudah untuk ini adalah menghapus panggilan ke cmd.Dispose dari ExecSql dan bukannya memanggil fungsi Anda seperti ini:

public void PopulateLocalData() 
{ 
   using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
   {
       cmd.CommandType = System.Data.CommandType.StoredProcedure; 
       cmd.CommandText = "usp_PopulateServiceSurveyLocal"; 
       DataLayer.DataProvider.ExecSQL(ConnString, cmd);
   }
} 

Salah satu kekhawatiran saya adalah jika kesalahan terjadi saat mengeksekusi query, baris cmd.disposisi tidak akan pernah dieksekusi. Apakah itu berarti akan terus menggunakan memori yang tidak akan pernah dirilis?

Secara kebetulan, SqlClient.SqlCommand tidak perlu dibuang. Ini, bagaimanapun, adalah detail implementasi yang tidak boleh Anda andalkan - aturan umum masih: Jika diimplementasikan IDisposable, buang itu. (SqlCeClient.SqlCeCommand, sebagai contoh, tidak harus dibuang ...)


0
2018-04-23 14:11



Nah untuk permulaan, Anda bisa mengubahnya menjadi:

public static int ExecSQL(string sqlConnString, System.Data.SqlClient.SqlCommand cmd)
{ 
    int rowsAffected;
    try
    {
        using (SqlConnection conn = new SqlConnection(sqlConnString))
        {
            conn.Open();
            cmd.Connection = conn;
            rowsAffected = cmd.ExecuteNonQuery();
        }
    } finally {
        cmd.Dispose();
    }
    return rowsAffected;
}

Selain itu, saya biasanya memisahkan bisnis dan lapisan data lebih banyak daripada yang Anda lakukan. Lapisan bisnis saya akan memanggil metode "GetLocalSurvey" di lapisan data, yang akan menangani semua omong kosong SQL.


-1
2018-04-23 13:54