轉帖|其它|編輯:郝浩|2010-12-28 17:07:16.000|閱讀 638 次
概述:本文主要介紹如何輕松實現Linq To Sql 簡單的單表批量刪除,希望對大家有幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
今天在網上看到老趙前輩的擴展LINQ to SQL:使用Lambda Expression批量刪除數據,我看完了文章,還沒有看源代碼,我一般都習慣于在看別人的代碼前,思考一下如果我來實現我會如何實現。我想了許久操作表達式樹操作二元表達式(BinaryExpression)我是肯定困難的,對于表達式類庫的了解不多,用了Reflector反射,結果什么都看不見,也許我的Reflector版本低了,沒有更新。我就放棄了這種實現方式,我想有沒有其他的方式呢?最終我覺得可以操作生成sql執行同樣可以達到目的,也許更簡單化。
如何獲取sql呢,Linq中有db.GetCommand(IQueryable )方法,DBCommand的CommandText就是sql了,那我們如何獲取IQueryable 呢,我的第一感覺就是where方法。所以就有下面的語句了,IQueryable q = source.Where(query).AsQueryable(); DbCommand cmd = db.GetCommand(q);
現在我們等到了查詢sql,如何轉化為Delete呢,我用了正則表達式匹配。就得到了下面完全代碼:
public static class TableExtension
{
/// <summary>
/// 單表操作批量刪除
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="query"></param>
/// <returns></returns>
public static int Delete<T>(this System.Data.Linq.Table<T> source, Expression<Func<T, bool>> query)
where T : class
{
if (source == null)
throw new ArgumentException("source");
if (query == null)
throw new ArgumentException("query");
//query = t => true;
//為空DELETE FROM [dbo].[test] 全刪除;個人覺得為空全刪除,很不人道,所以還是拋異常
System.Data.Linq.DataContext db = source.Context;
IQueryable q = source.Where(query).AsQueryable();
DbCommand cmd = db.GetCommand(q);
string sql = cmd.CommandText;
string regex =
@"from\s*\[\s*dbo\s*\]\s*\.\s*\[\s*\w+\s*\]\s*(?<tableparam>(as\s*(?<tablepname>(\[\s*\w+\s*\]))))(\.|(\r)|(\n))*";
MatchCollection matches = Regex.Matches(sql, regex, RegexOptions.Multiline | RegexOptions.IgnoreCase);
Debug.Assert(matches != null, "regex match :null");
Debug.Assert(matches.Count == 1, "regex match length :" + matches.Count);
if (matches != null && matches.Count > 0)
{
Match match = matches[0];
sql = ("DELETE " + match.Value.Replace(match.Groups["tableparam"].Value, "") +
sql.Substring(match.Index + match.Length)).Replace(match.Groups["tablepname"].Value + ".", " ");
List<object> dbparams = new List<object>();
foreach (SqlParameter item in cmd.Parameters)
{
SqlParameter p = new SqlParameter(item.ParameterName, item.SqlDbType, item.Size);
p.Value = item.Value;
dbparams.Add(item.Value);
}
q = null;
cmd = null;
matches = null;
Debug.WriteLine("delete sql :" + sql);
return db.ExecuteCommand(sql, dbparams.ToArray());
}
return 0;
}
現在我們可以進行批量刪除了,如:
DataContext.test.Delete(t => t.id > 0 && t.name.Contains("test") || new string[] { "12", "34", "45" }.Contains(t.name)
&& t.name.Length >1);
是不是很簡單:看看Debug輸出的sql:
在看一個:
DataContext.Orders.Delete(t => !t.EmployeeID1.HasValue);
這個擴展中的缺點:
1:只針對對單表操作,不支持linq的連接,如:DataContext.test.Delete(t => t.Orders.OrderID > 0);我這個我認為這個可以通過一個更復雜正則表達式完成。還有一種思路更簡潔,就是通過sql server支持的表變量或者是臨時表先查詢出結果,在根據主鍵實現刪除。也許你會說可以寫成存儲過程,我個人不喜歡它,我一般盡量在程序中TSQL,移植性好,除非性能考慮采用存儲過程。
2:事務處理:在這里只是一個先前的測試Demo,所以么有考慮。我覺得我們可以建立一個類來管理sql語句或者查詢條件表達式在調用save方法時候進行內部事務操作(我一般不喜歡將事務顯示在外部,因為我覺得事務很費資源,等待時間過長數據庫容易崩潰,或者對表的鎖定等,不知道這個想法對不對,請大家給個建議)。現在可以在外部事務操作就是有點像ado.net了,呵呵麻煩。
優點:
1:可以支持復雜的表達式,想老趙提到的"item.Introduction.Length < 10",以及后面評論中提到的in、like等。
2:實現簡單,操作簡單,這是最重要的,代碼很容易理解。
3:執行不需要從數據庫里取出實體在執行,這是Linq的做法。更符合我們的習慣。我看見在老趙博客最后一個評論說它用EF也實現了批量刪除,它的那種方式是取出實體在delete,其實并不是EF特有的,Linq也完全可以實現,就幾行代碼而已。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載