删除前是否应该检查行是否存在?

发布于 2024-10-08 07:14:01 字数 1126 浏览 0 评论 0原文

我使用 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 )。自从加载实体后,实体可能已被修改或删除。)
我是否应该像这样往返数据库来检查该行是否存在:

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 命令删除该行。

什么是更好的做法?

I'm using Mssql as the db and EF4 as the ORM/DAL.
My question is about the following code:

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();
}

If the row exists this works very well, if not I get an exception(Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.)
Should I make a round trip to the database to check if the row exists like this:

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();
    }
}

I think that extra round trip is kinda unnecessary because without the EF, with plain SQL I could simply delete the row with a single DELETE command.

What would be a better practice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

天冷不及心凉 2024-10-15 07:14:01

该错误是实体框架乐观并发的副作用。

基本上,其他人可能在您检索记录期间删除了该记录。或者也许您在该代码之前已经对实体做了一些操作。

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

是的,您可以安全起见并再次获取记录,或者您可以使用 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 乐观并发的优秀文章 此处,这进一步详细解释了为什么您会得到该错误,以及可以采取哪些步骤来解决该错误。

That error is a side effect of Entity Framework's optimistic concurrency.

Basically, someone else may have deleted the record in between you retrieving it. Or maybe you have done something with the entity before that code.

Try running it in an isolate environment (e.g a unit test) to see if you still get the issue.

Yes, you could play it safe and get the record again, or you could use 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();
    }
}

On a side note - maybe it's because your method is static? How are you instantiating your context? I hope you're not using a singleton. :(

There is an excellent article on EF optimistic concurrency here, which explains in further detail why you're getting that error, and what steps can be done to counter it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文