天天看點

Linq To Sql 簡單的單表批量删除

      如何擷取sql呢,linq中有db.getcommand(iqueryable )方法,dbcommand的commandtext就是sql了,那我們如何擷取iqueryable 呢,我的第一感覺就是where方法。是以就有下面的語句了,iqueryable q = source.where(query).asqueryable();     dbcommand cmd = db.getcommand(q);

     現在我們等到了查詢sql,如何轉化為delete呢,我用了正規表達式比對。就得到了下面完全代碼:

Linq To Sql 簡單的單表批量删除
Linq To Sql 簡單的單表批量删除

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;

        }

Linq To Sql 簡單的單表批量删除

 現在我們可以進行批量删除了,如:

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:

Linq To Sql 簡單的單表批量删除

在看一個:

<a href="http://images.cnblogs.com/cnblogs_com/whitewolf/windowslivewriter/linqtosql_13895/image_4.png"></a>

datacontext.orders.delete(t =&gt; !t.employeeid1.hasvalue);

Linq To Sql 簡單的單表批量删除

這個擴充中的缺點:

1:隻針對對單表操作,不支援linq的連接配接,如:datacontext.test.delete(t =&gt; t.orders.orderid &gt; 0);我這個我認為這個可以通過一個更複雜正規表達式完成。還有一種思路更簡潔,就是通過sql server支援的表變量或者是臨時表先查詢出結果,在根據主鍵實作删除。也許你會說可以寫成存儲過程,我個人不喜歡它,我一般盡量在程式中tsql,移植性好,除非性能考慮采用存儲過程。

2:事務處理:在這裡隻是一個先前的測試demo,是以麼有考慮。我覺得我們可以建立一個類來管理sql語句或者查詢條件表達式在調用save方法時候進行内部事務操作(我一般不喜歡将事務顯示在外部,因為我覺得事務很費資源,等待時間過長資料庫容易崩潰,或者對表的鎖定等,不知道這個想法對不對,請大家給個建議)。現在可以在外部事務操作就是有點像ado.net了,呵呵麻煩。

優點:

1:可以支援複雜的表達式,想老趙提到的“item.introduction.length &lt; 10“,以及後面評論中提到的in、like等。

2:實作簡單,操作簡單,這是最重要的,代碼很容易了解。

3:執行不需要從資料庫裡取出實體在執行,這是linq的做法。更符合我們的習慣。我看見在老趙部落格最後一個評論說它用ef也實作了批量删除,它的那種方式是取出實體在delete,其實并不是ef特有的,linq也完全可以實作,就幾行代碼而已。

    還想多寫一些優點,暫時就想到這些,有什麼bug或者建議請大家一定要指出。還有就是不知道這樣對記憶體有麼有影響,還沒有來得及測試。

     我個人覺得其實計算機的東西都是我們生活中簡單的問題運用,就在個人的思維了,就和前面講的老外linq組合查詢的predicateextensions類一樣。

    恩現在趕緊去看看老趙前輩的實作方式了,還沒來得及看過一行代碼呢,不知對事務、多表的支援如何。