LINQ to SQL异常:除Contains运算符外,本地序列不能用于查询运算符的LINQ to SQL实现

时间:2013-07-19 16:19:43

标签: c# linq-to-sql

我知道这在SO上是重复的,但我无法弄清楚如何在我的特定代码中使用contains运算符:

我在数据库中有5个预订:

ID,Booking,Pren,ReservationCode

1,VisitHere,1,1000A

2,VisitHere,1,1000A

3,VisitHere,1,1000A

4,VisitThere,2,2000A

5,VisitThere,2,2000A

    public int SpecialDelete(DataContext db, IEnumerable<BookingType> bookings) {

        var rescodes = (from b in bookings
                        select b).Distinct().ToArray();
        // Code Breaks here
        IEnumerable<BookingType> bookingsToDelete = db.GetTable<BookingType>().Where(b => bookings.Any(p => p.Pren == b.Pren && p.ReservationCode == b.ReservationCode));

        int deleted = bookingsToDelete.Count();
        db.GetTable<BookingType>().DeleteAllOnSubmit(bookingsToDelete);
        db.SubmitChanges();

        return deleted;
    }

当我将第一条记录传递给此方法(1,VisitHere,1,1000A)时,我希望它能够检索ID 1,2和3,而不是4和5。

我可以通过匹配Pren和ReservationCode来实现。

我怎么能这样做.Any和.All运算符抛出上述异常?

注意:该方法必须接受预订列表,因为参数将始终是传递给方法的多个预订,我只使用一个预订作为示例。

编辑:我基本上需要LINQ2SQL来生成一堆像这样的SQL语句(假设我要删除数据库中的所有记录):

DELETE
FROM Bookings b
WHERE b.ReservationCode = '1000A' AND b.Pren = 1

DELETE
FROM Bookings b
WHERE b.ReservationCode = '2000A' AND b.Pren = 2

3 个答案:

答案 0 :(得分:1)

如果服务器上有准临时表,该怎么办?您可以将列表值放在那里。

这是ORM的真正问题。本地和远程功能之间存在很多不匹配。

我甚至尝试使用.Range生成一个远程列表来加入,但它也不起作用。

基本上你必须以某种方式重新安排你的数据岛(即pren和rs的列表来自哪里?它在服务器上的某个地方?)或者将你的一个本地集合上传到服务器上的暂存区域。

答案 1 :(得分:1)

您遇到的错误是尝试引导您使用传入简单数组的.Contains方法。默认情况下,它会将该数组转换为In子句,格式为:

Where foo In ("b1", "B2", "B3")

请注意,您不能在In子句中执行多维数组(正如您所需要的那样)。由于您无法将服务器端加入本地阵列,因此只要您具有复合密钥关系,您的选项就会受到限制。

如果您不需要获取行以删除它们,那么仅使用Context的ExecuteCommand来发出删除可能会更快。只需确保参数化您的查询(请参阅http://www.thinqlinq.com/Post.aspx/Title/Does-LINQ-to-SQL-eliminate-the-possibility-of-SQL-Injection

string deleteQuery = "DELETE FROM Bookings b WHERE b.ReservationCode = {0} AND b.Pren = {1}";
foreach (var bookingType in bookings)
{
    db.ExecuteCommand(deleteQuery, bookingType.ReservationCode, bookingType.Preen);
}

答案 2 :(得分:0)

错误消息显示“除包含运算符外”。您是否考虑过使用Contains运算符?它应该做同样的事情。

所以来自

IEnumerable<BookingType> bookingsToDelete = db.GetTable<BookingType>().Where(b => bookings.Any(p => p.Pren == b.Pren && p.ReservationCode == b.ReservationCode));

IEnumerable<BookingType> bookingsToDelete = db.GetTable<BookingType>().Where(b => bookings.Contains(p => p.Pren == b.Pren && p.ReservationCode == b.ReservationCode));

我意识到列表不会包含相同的对象,因此您可能需要执行以下操作:

bookings.Select(booking => booking.PrimaryKeyOfAwesome).Contains(b => b.PrimaryKeyOfAwesome) etc etc. 


为清晰度而编辑

编辑谦虚 好吧,所以在实际重新创建整个设置之后,我意识到我的解决方案不起作用,因为有两个参数,而不仅仅是一个。道歉。这就是我最终提出的,它起作用,但真的是一个可怕的解决方案,不应该使用。我把它包括在这里只是为了关闭;)

        public static int SpecialDelete(DataContext db, IEnumerable<BookingType> bookings)
        {
            var compositeKeys = bookings.Select(b => b.Pren.ToString() + b.ReservationCode).Distinct();
            IEnumerable<BookingType> bookingsToDelete = db.GetTable<BookingType>().Where(b => compositeKeys.Contains(b.Pren.ToString() + b.ReservationCode));

            int deleted = bookingsToDelete.Count();
            db.GetTable<BookingType>().DeleteAllOnSubmit(bookingsToDelete);
            db.SubmitChanges();

            return deleted;
        }