我应该在删除之前检查一行是不是存在吗?

Posted

技术标签:

【中文标题】我应该在删除之前检查一行是不是存在吗?【英文标题】:Should I check if a row exists before deletion?我应该在删除之前检查一行是否存在吗? 【发布时间】:2010-12-15 22:22:50 【问题描述】:

我使用 Mssql 作为数据库,使用 EF4 作为 ORM/DAL。 我的问题是关于以下代码:

public static void DeleteBuilding(int buildingId, int countryId)

    PlayerBuilding playerBuilding = new PlayerBuilding()
    
        CountryID = countryId,
        BuildingID = buildingId
    ;
    Entities.PlayerBuildings.Attach(playerBuilding);
    Entities.PlayerBuildings.DeleteObject(playerBuilding);
    Entities.SaveChanges();

如果行存在,这很好用,如果不存在我得到一个异常(存储更新、插入或删除语句影响了意外的行数 (0)。实体可能有自加载实体后被修改或删除。刷新 ObjectStateManager 条目。) 我是否应该像这样来回访问数据库以检查该行是否存在:

public static void DeleteBuilding(int buildingId, int countryId)

    PlayerBuilding playerBuilding = (from p in Entities.PlayerBuildings
                                     where p.BuildingID == buildingId && p.CountryID == countryId
                                     select p).FirstOrDefault();
    if (playerBuilding != null)
    
        Entities.PlayerBuildings.DeleteObject(playerBuilding);
        Entities.SaveChanges();
    

我认为额外的往返是不必要的,因为没有 EF,使用纯 SQL,我可以使用单个 DELETE 命令简单地删除该行。

什么是更好的做法?

【问题讨论】:

【参考方案1】:

该错误是 Entity Framework 的乐观并发的副作用。

基本上,其他人可能在您检索记录之间删除了该记录。或者,您可能在该代码之前对实体进行了某些操作。

尝试在隔离环境中运行它(例如单元测试),看看您是否仍然遇到问题。

是的,您可以放心地再次获得记录,或者您可以使用 ObjectContext.Refresh

public static void DeleteBuilding(int buildingId, int countryId)

    PlayerBuilding playerBuilding = new PlayerBuilding()
    
        CountryID = countryId,
        BuildingID = buildingId
    ;

    try
    
       Entities.PlayerBuildings.Attach(playerBuilding);
       Entities.PlayerBuildings.DeleteObject(playerBuilding);
       Entities.SaveChanges();
    
    catch (OptimisticConcurrencyException)
    
       Entities.Refresh(RefreshMode.ClientWins, playerBuilding);
       Entities.SaveChanges();
    

附带说明 - 可能是因为您的方法是静态?你如何实例化你的上下文?我希望你没有使用单例。 :(

有一篇关于 EF 乐观并发here 的优秀文章,其中更详细地解释了为什么会出现该错误,以及可以采取哪些步骤来解决它。

【讨论】:

感谢 RPM 的评论,但这不是一个乐观的并发问题。我正在使用本地开发人员计算机,尝试了非静态方法,这也不是问题。使用此方法实例化上下文:dotnetslackers.com/articles/ado_net/…。使用正常的方式来实例化上下文而不改变任何东西。 看看这篇文章——那篇文章中的错误和你的完全一样。您是否尝试在单元测试(隔离)中运行上述代码?另外-您提供的那篇文章中的哪种方式实例化了上下文? (那篇文章中有多种方法) 我使用了 UnitOfWorkScope 方法,但这不是问题所在。即使我使用旧方式(MyContext context = new MyContext()) 实例化上下文,也会继续显示相同的错误。我认为它与并发无关,显示错误是因为我正在尝试删除上下文中不存在的对象。 好的。您是否在我的回答中尝试过上面的“刷新”方法?附带说明一下,当您知道对象不存在时,您是否应该首先调用此方法?

以上是关于我应该在删除之前检查一行是不是存在吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查消息是不是存在? (discord.js)

在插入之前检查是不是存在时我的语法错误

如何检查 Makefile 中是不是存在文件以便删除它?

如何在合并数据集之前检查行是不是存在(SQL Server)

在插入 BigQuery 表之前检查数据是不是已经存在(使用 Python)

如何在显示列之前检查 SELECT 语句是不是存在