天天看点

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类一样。

    恩现在赶紧去看看老赵前辈的实现方式了,还没来得及看过一行代码呢,不知对事务、多表的支持如何。