Dapper

2014-04-11 24 views
7

'de arabelleğe alınmamış sorgularla bağlantıyı yönetme Dapper'u kullanmaya başladım, her şey güzel ve kolay görünüyor, ancak kafamı karıştıran bir şey var: Bağlantı Yönetimi. gereğinceDapper

documentation:

Zarif bağlantınızın en yaşam döngüsünü yönetmek değil

, onu alır bağlantısı açıktır varsayar VE (MARS etkin değilse)

numaralandırılırken hiç mevcut datareaders vardır

Bunun ışığında bunu benim depo yöntemlerimin uygulanmasında yapmaya başladım:

using (var db = new SqliteConnection(connectionString)) { 
    // call Dapper methods here 
} 

Çok sayıda kayıt bulunan bir tabloya rastladım, bu yüzden 'u Query<> yöntemine geçirerek bir IEnumerable<T> döndürdüm ve ön uçta numaralandırmayı numaralandırmaya başladığımda, bağlantının kapalı olduğunu belirten bir istisna ve aramalarımı bir önceki kullanım bloğu ile sarmaladığımdan beri bekletilen.

Soru: Bunu çözmenin en iyi yolu?
Yan soru: Bağlantıyı yönetme yolu, tercih etmenin yolu bu mu?

+0

, ben tamponlu kullandık. – wintercyborg

cevap

10

bu depo desen önerirdim: sizin için GetConnection yönteminin birinci aşırı kullanmak isteyen tamponlu sorguları için

public class Repository 
{ 
    private readonly string _connectionString; 

    public Repository(string connectionString) 
    { 
     _connectionString = connectionString; 
    } 

    protected T GetConnection<T>(Func<IDbConnection, T> getData) 
    { 
     using (var connection = new SqlConnection(_connectionString)) 
     { 
      connection.Open(); 
      return getData(connection); 
     } 
    } 

    protected TResult GetConnection<TRead, TResult>(Func<IDbConnection, TRead> getData, Func<TRead, TResult> process) 
    { 
     using (var connection = new SqlConnection(_connectionString)) 
     { 
      connection.Open(); 
      var data = getData(connection); 
      return process(data); 
     } 
    } 
} 

olmayan tamponlu İşlemekte veriler için geri arama specifing, ikinci kullanın:

public class MyRepository : Repository 
{ 
    public MyRepository(string connectionString) : base(connectionString) 
    { 
    } 

    public IEnumerable<MyMapObject> GetData() 
    { 
     return GetConnection(c => c.Query<MyMapObject>(query)); 
    } 

    public IEnumerable<ResultObject> GetLotsOfData(Func<IEnumerable<MyMapObject>, IEnumerable<ResultObject>> process) 
    { 
     return GetConnection(c => c.Query<MyMapObject>(query, buffered: false), process); 
    } 
} 

çok temel kullanım:

static void Main(string[] args) 
{ 
    var repository = new MyRepository(connectionString); 
    var data = repository.GetLotsOfData(ProcessData); 
} 

public static IEnumerable<ResultObject> ProcessData(IEnumerable<MyMapObject> data) 
{ 
    foreach (var record in data) 
    { 
     var result = new ResultObject(); 
     //do some work... 
     yield return result; 
    } 
} 

Ama akılda tutulması - Bu durumda bağlantı çok uzun süre açılabilir ...

+0

Ohh adamım, ne düşünüyordum. Bana "verim" anahtar kelimesini hatırlattığın için teşekkür ederim Sergio. Neden kullanımını unuttum bilmiyorum. Bir şey olsa da, bu çalışmayı elde etmek için tüm bu sıhhi tesisata ihtiyacınız yoktur, sadece doğrudan depodaki yöntem uygulamasında "getiri geri dönüşü sonucunu" kullanabilirsiniz. Başka kimse daha iyi bir cevapla gelmediyse size ödül vereceğim. Teşekkür ederim. –

+0

Belki de, bağlantının Dapper'ın daha yeni sürümünde açık olması gerekmez. SqlMapper sınıfı, bağlantının durumunu kontrol eder ve kapalıysa, üzerinde 'Open()' ifadesi bulunur. –

6

@Sergio, AWESOME! Böyle harika bir desen için teşekkürler. Dapper'ın async yöntemleri ile kullanabilmem için biraz uyumsuz olarak değiştirdim. İstek zincirimin tümünün uyumsuzluğunu denetleyiciden DB'ye kadar geri getiriyor! Muhteşem! Böyle Dapper ile

public abstract class BaseRepository 
{ 
    private readonly string _ConnectionString; 

    protected BaseRepository(string connectionString) 
    { 
     _ConnectionString = connectionString; 
    } 

    // use for buffered queries 
    protected async Task<T> WithConnection<T>(Func<IDbConnection, Task<T>> getData) 
    { 
     try 
     { 
      using (var connection = new SqlConnection(_ConnectionString)) 
      { 
       await connection.OpenAsync(); 
       return await getData(connection); 
      } 
     } 
     catch (TimeoutException ex) 
     { 
      throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex); 
     } 
     catch (SqlException ex) 
     { 
      throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex); 
     } 
    } 

    // use for non-buffeed queries 
    protected async Task<TResult> WithConnection<TRead, TResult>(Func<IDbConnection, Task<TRead>> getData, Func<TRead, Task<TResult>> process) 
    { 
     try 
     { 
      using (var connection = new SqlConnection(_ConnectionString)) 
      { 
       await connection.OpenAsync(); 
       var data = await getData(connection); 
       return await process(data); 
      } 
     } 
     catch (TimeoutException ex) 
     { 
      throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex); 
     } 
     catch (SqlException ex) 
     { 
      throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex); 
     } 
    } 
} 

Kullanımı: false ve şık w/my bağlantı sorunu düzeltildi: Bu başkası yardımcı olur Ne olur ne

public class PersonRepository : BaseRepository 
{ 
    public PersonRepository(string connectionString): base (connectionString) { } 

    // Assumes you have a Person table in your DB that 
    // aligns with a Person POCO model. 
    // 
    // Assumes you have an existing SQL sproc in your DB 
    // with @Id UNIQUEIDENTIFIER as a parameter. The sproc 
    // returns rows from the Person table. 
    public async Task<Person> GetPersonById(Guid Id) 
    { 
     return await WithConnection(async c => 
     { 
      var p = new DynamicParameters(); 
      p.Add("Id", Id, DbType.Guid); 
      var people = await c.QueryAsync<Person>(sql: "sp_Person_GetById", param: p, commandType: CommandType.StoredProcedure); 
      return people.FirstOrDefault(); 
     }); 
    } 
} 
İlgili konular