DBCommand 인스턴스는 어디에서 만들어야합니까?
-
12-09-2019 - |
문제
나는 두 가지 선택이있는 것 같습니다.
- 내 수업을 구현하십시오
IDisposable
. 내DbCommand
인스턴스로private readonly
필드 및 생성자에 사용하는 매개 변수를 추가하십시오. 데이터베이스에 편지를 쓰고 싶을 때 마다이 매개 변수에 바인딩 (동일한 명령 인스턴스를 재사용)Connection
그리고Transaction
속성, 전화하십시오ExecuteNonQuery
. 에서Dispose
방법, 호출Dispose
이 분야에서. - 데이터베이스에 글을 쓰고 싶을 때마다 쓰기
using(var cmd = new DbCommand("...", connection, transaction))
명령의 사용과 관련하여 호출하기 전에 매개 변수를 추가하고 매번 바인딩합니다.ExecuteNonQuery
. 각 쿼리마다 새 명령이 필요하지 않다고 가정합니다. 데이터베이스를 열 때마다 새 명령 만 (맞습니까?).
이 두 가지 모두 다소 우기적이고 부정확 해 보입니다.
#1의 경우,이 수업이 지금이 수업을하는 것은 내 사용자에게 성가신 일입니다. IDisposable
몇 가지를 사용했기 때문입니다 DbCommand
S (신경 쓰지 않는 구현 세부 사항이어야합니다). 나는 또한 a를 유지하는 것이 다소 의심 스럽다 DbCommand
주변 인스턴스가 실수로 데이터베이스를 잠그있을 수 있습니까?
#2의 경우, 데이터베이스에 특히 매개 변수 어드딩을 사용하고 싶을 때마다 많은 작업 (.NET 객체)에서 많은 작업을 수행하는 것처럼 느껴집니다. 매번 같은 객체를 만드는 것 같습니다.
참고로 #1을 사용하여 현재 코드가 있습니다.
using System;
using System.Net;
using System.Data.SQLite;
public class Class1 : IDisposable
{
private readonly SQLiteCommand updateCookie = new SQLiteCommand("UPDATE moz_cookies SET value = @value, expiry = @expiry, isSecure = @isSecure, isHttpOnly = @isHttpOnly WHERE name = @name AND host = @host AND path = @path");
public Class1()
{
this.updateCookie.Parameters.AddRange(new[]
{
new SQLiteParameter("@name"),
new SQLiteParameter("@value"),
new SQLiteParameter("@host"),
new SQLiteParameter("@path"),
new SQLiteParameter("@expiry"),
new SQLiteParameter("@isSecure"),
new SQLiteParameter("@isHttpOnly")
});
}
private static void BindDbCommandToMozillaCookie(DbCommand command, Cookie cookie)
{
long expiresSeconds = (long)cookie.Expires.TotalSeconds;
command.Parameters["@name"].Value = cookie.Name;
command.Parameters["@value"].Value = cookie.Value;
command.Parameters["@host"].Value = cookie.Domain;
command.Parameters["@path"].Value = cookie.Path;
command.Parameters["@expiry"].Value = expiresSeconds;
command.Parameters["@isSecure"].Value = cookie.Secure;
command.Parameters["@isHttpOnly"].Value = cookie.HttpOnly;
}
public void WriteCurrentCookiesToMozillaBasedBrowserSqlite(string databaseFilename)
{
using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + databaseFilename))
{
connection.Open();
using (SQLiteTransaction transaction = connection.BeginTransaction())
{
this.updateCookie.Connection = connection;
this.updateCookie.Transaction = transaction;
foreach (Cookie cookie in SomeOtherClass.GetCookieArray())
{
Class1.BindDbCommandToMozillaCookie(this.updateCookie, cookie);
this.updateCookie.ExecuteNonQuery();
}
transaction.Commit();
}
}
}
#region IDisposable implementation
protected virtual void Dispose(bool disposing)
{
if (!this.disposed && disposing)
{
this.updateCookie.Dispose();
}
this.disposed = true;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
~Class1()
{
this.Dispose(false);
}
private bool disposed;
#endregion
}
해결책
domenic, sqlitecommand를 처분하면 활성 리더가 독자를 처분하도록 신호를 보내고 매개 변수 및 연결 참조를 NULL에 설정합니다.
실행 된 리더를 올바르게 폐기하고 연결을 닫고 폐기하는 한 명령을 캐싱하여 자원이 누출 될 위험이 없습니다.
따라서 캐시 된 명령을 재사용하고 단순히 매개 변수에 값을 할당하는 것이 가장 효율적인 구현입니다.
.prepare ()는 a noop
sqlitecommand에서는 그곳에있는 이점이 없습니다.
다른 팁
데이터베이스 객체 수명주기를 처리하는 단일 "올바른 방법"은 없습니다. 그것은 모두 응용 프로그램 요구에 따라 다릅니다.
내 개인적인 취향은 코드를 가능한 한 간단하게 유지하는 것입니다. 필요에 따라 명령 및 매개 변수 개체를 재현하는 경향이 있습니다. 이것은 내 기능을 가능한 한 자체적으로 포함시킬 수있게합니다. 그것은 내가해야 할 모든 팩토링을 크게 단순화했습니다.
재생성 물체의 성능에 관심이 있다면 프로파일 러를로드하고 병 목이 어디에 있는지 확인해야합니다. 내가 구축 한 응용 프로그램에서 DBCommand 객체를 만드는 데 소요되는 시간이 쿼리를 실행하는 데 소요되는 시간과 비교하여 매우 중요하지 않다는 것을 알았습니다.
동일한 연결로 명령을 재사용하면 SQLServer를 발견했습니다. 다른 연결과 거래를 테스트 할 계획이지만 더 빠른 것으로 보입니다.