如何擷取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:
在看一個:
<a href="http://images.cnblogs.com/cnblogs_com/whitewolf/windowslivewriter/linqtosql_13895/image_4.png"></a>
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也完全可以實作,就幾行代碼而已。
還想多寫一些優點,暫時就想到這些,有什麼bug或者建議請大家一定要指出。還有就是不知道這樣對記憶體有麼有影響,還沒有來得及測試。
我個人覺得其實計算機的東西都是我們生活中簡單的問題運用,就在個人的思維了,就和前面講的老外linq組合查詢的predicateextensions類一樣。
恩現在趕緊去看看老趙前輩的實作方式了,還沒來得及看過一行代碼呢,不知對事務、多表的支援如何。