這邊以Dapper Repository代碼優化過程,來帶讀者了解此概念,代碼流程邏輯很簡單 : 查一筆會員的資料接著刪除。
接著使用Dapper做一個UserRepository代碼,如下,可以發現問題 : 「每一個方法都會新增一個新的Connection」
,就算SqlConnection底層預設使用連線池,也不能這樣浪費資源。
//使用方式
void Main()
{
var userRepository = new UserRepository();
var user = userRepository.Get("user01");
userRepository.Delete(user);
}
public class UserRepository
{
public User Get(string Id)
{
using (var cnn = Db.GetConnection())
{
return cnn.QueryFirst<User>("select * from User where Id = @Id", new { Id });
}
}
public int Delete(User user)
{
using (var cnn = Db.GetConnection())
{
return cnn.Execute("delete User where Id = @Id", new { user.Id });
}
}
}
接著優化成由外層掌控Connection的建立
,並帶入建構式讓多個方法共用一個Connection
,解決資源浪費的情況。但是還是有問題 : 「假設有多個表格必須要建立多個Repository」
。
void Main()
{
using (var cn = Db.GetConnection())
{
var userRepository = new UserRepository(cn);
var user = userRepository.Get("user01");
userRepository.Delete(user);
}
}
public class UserRepository
{
private readonly IDbConnection _Connection;
public UserRepository(IDbConnection connection) => this._Connection = connection;
public User Get(string Id)=> _Connection.QueryFirst<User>("select * from User where Id = @Id", new { Id });
public int Delete(User user)=> _Connection.Execute("delete User where Id = @Id", new { user.Id });
}
為了解決這問題,可以使用依賴泛型
來處理,就不需要每個表格都建立一個Repository
void Main()
{
using (var cn = Db.GetConnection())
{
var userRepository = new Repository<User>(cn);
var user = userRepository.Get("user01");
userRepository.Delete(user.Id);
}
}
public class Repository<T>
{
private readonly IDbConnection _Connection;
private readonly string _TableName ;
private readonly string _IdName ;
public Repository(IDbConnection connection,string idName = "Id") {
this._Connection = connection;
this._TableName = typeof(T).Name;
this._IdName = idName;
}
public T Get(string Id) => _Connection.QueryFirst<T>($"select * from [{this._TableName}] where [{this._IdName}] = @Id", new { Id });
public int Delete(string Id) => _Connection.Execute($"delete [{this._TableName}] where [{this._IdName}] = @Id", new { Id });
}
是否還可以優化?
可以的,以上例子能發現CRUD的動作邏輯都一樣
,那麼乾脆連Repository都不需要建立,直接依賴於Connection跟泛型
,所以就有了Dapper.Contrib的誕生,代碼簡化成以下方式 :
void Main()
{
using (var cn = Db.GetConnection())
{
var user = cn.Get<User>("user01");
cn.Delete<User>(user);
}
}
接著延伸一個問題,舉例:假如想要靈活的查詢性別為男性,年紀少於18歲的User資料怎麼辦?
假如需要靈活性,使用LINQ + Expression Func
可以動態組出篩選條件是最好的方式,而不是使用寫死的ID參數。
滿足以上需求的現有工具就是EntityFramework,代碼可以簡化成 :
void Main()
{
using (var db = dbContext)
{
var users = db.Users.Where(w=>w.Gender=="M" && w.Age<18);
db.Users.RemoveRange(users);
db.SaveChanges();
}
}
這就是為何簡單查詢優先使用EF的原因,簡單代表邏輯規律
,規律的需求可以發現隨著專案、時間的推移,也只會做成像EF LINQ一樣,那何不一開始就使用EF呢?