【问题标题】:Error while deleting a record with LINQ使用 LINQ 删除记录时出错
【发布时间】:2026-01-13 13:35:01
【问题描述】:

我尝试将 SQL 删除命令更改为 LINQ。这是我的 SQL 命令:

DELETE FROM [TrackPoints]
WHERE [RouteFK] IN (SELECT RouteId
                    FROM Routes
                    WHERE UserId = @UserId)

这是我编写的 LINQ 代码:

int UID =1;
FirstDataContext aspnetdb = new FirstDataContext();
var res1 = from q1 in aspnetdb.Routes
           where q1.UserId == UID
           select q1.RouteId;
foreach (var k in res1)
{
    var eigen = from p in aspnetdb.Trackpoints
                where p.RouteFK == k
                select p.TrackPointId;

    aspnetdb.Trackpoints.DeleteOnSubmit(eigen.First());
    aspnetdb.SubmitChanges();
}

但在这一行我有一个错误:

aspnetdb.Trackpoints.DeleteOnSubmit(eigen.First());

说:

'System.Data.Linq.Table.DeleteOnSubmit(LINQ_Test.Trackpoint)' 的最佳重载方法匹配有一些无效参数

我该怎么办?

【问题讨论】:

  • LINQ to SQL 或实体框架?
  • LINQ to SQL。能否请您简要解释一下 LINQ to SQL 和实体框架之间的区别?
  • LINQ to SQL 是 Microsoft 在 Entity Framework 之前的 ORM,现在已被废弃和过时。

标签: c# .net linq linq-to-sql exception-handling


【解决方案1】:

使用这个:

var eigen = (from p in aspnetdb.Trackpoints
            where p.RouteFK == k
            select p).First();

或者更短的:

var eigen = aspnetdb.Trackpoints.First(p => p.RouteFK == k);

因为它返回Trackpoint

而您的 select p.TrackPointId 返回 Int


var r = from r in aspnetdb.Routes
        join p in aspnetdb.Trackpoints on p.RouteId equals r.RouteFK
        where r.UserId == UID
        select p;

foreach (var x in r)
{
    aspnetdb.Trackpoints.DeleteOnSubmit(x);
}
aspnetdb.SubmitChanges();

【讨论】:

  • @Kabi:还要注意调用DeleteAllOnSubmit 以进一步简化代码的选项...
【解决方案2】:

问题在于您只是选择了 ID,而该 ID 与方法签名不匹配。我实际上会将您的代码更改为:

var entity = aspnetdb.Trackpoints.Where(p => p.RouteFK == k).Single();
aspnetdb.Trackpoints.DeleteOnSubmit(entity);

(当您将 select 子句更改为仅 select p 时,使用查询表达式变得毫无意义 - 一旦您使用方法调用语法,调用 Single 就有意义了或First 在同一语句中。根据abatishchev 的回答,这也可能是aspnetdb.Trackpoints.Single(p => p.RouteFK == k)。)

顺便说一句,这假设您肯定有给定 RouteFK 的 1 个(并且只有 1 个)实体。

在单个查询中选择所有您要删除的实体实际上可能会更好。例如:

var entitiesToDelete = from q1 in aspnetdb.Routes
                       where q1.UserId == UID
                       join p in aspnetdb.TrackPoints 
                         on q1.RouteID equals p.RouteFK
                       select p;

aspnetdb.Trackpoints.DeleteAllOnSubmit(entitiesToDelete);
aspnetdb.SubmitChanges();

或者,如果您在模型中正确设置了联接,则可能可以摆脱显式联接:

var entitiesToDelete = from q1 in aspnetdb.Routes
                       where q1.UserId == UID
                       select q1.Route; // Or Track, or whatever it is

aspnetdb.Trackpoints.DeleteAllOnSubmit(entitiesToDelete);
aspnetdb.SubmitChanges();

在这两种情况下,您都可以避免执行几乎一样多的查询。 (您避免了“n+1 选择”问题。)

【讨论】:

    【解决方案3】:

    DeleteOnSubmit 方法需要域对象。您的代码改为传递ID。此外,您缺乏检查该项目是否实际存在的条件。

    尝试将您的例程改写为:

            foreach (var k in res1)
            {
                var eigen = from p in aspnetdb.Trackpoints
                            where p.RouteFK == k
                            select p;
    
                var item = eigen.FirstOrDefault();
    
                if ( item != null )
                {
                  aspnetdb.Trackpoints.DeleteOnSubmit(item);
                  aspnetdb.SubmitChanges();
                }
    
            }
    

    【讨论】: