iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 26
1
Software Development

🌊 進階學習 ADO.NET、Dapper、Entity Framework 系列 第 26

【Entity Framework搭配Dapper】為何簡單動作優先使用EntityFramework

這邊以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呢?


上一篇
【Entity Framework搭配Dapper】使用時機
下一篇
【Entity Framework搭配Dapper】對應表格類別、增、刪、改使用Entity Framework
系列文
🌊 進階學習 ADO.NET、Dapper、Entity Framework 30

尚未有邦友留言

立即登入留言