1

我构建了我的第一个 MVC 项目并且在处理并发方面遇到了问题。在我决定添加并发处理之前,Web 应用程序运行良好(添加、编辑和删除)。

 //Entity class Line
public class Line
{
    [Key]
    [Required(ErrorMessage = "Please enter a line name")]
    public string Name { get; set; }

    [Required(ErrorMessage = "Please enter a Business Unit name")]
    public string BU { get; set; }

    [Required(ErrorMessage = "Please enter a Department name")]
    public string Department { get; set; }

    [Required(ErrorMessage = "Please enter a location of the line")]
    public string Location { get; set; }

    [Required(ErrorMessage = "Please enter a target output")]
    [Range(0.01, double.MaxValue, ErrorMessage = "Please enter a positive target output")]
    public int TargetOutput { get; set; }

    [Required(ErrorMessage = "Please enter a target yiel")]
    [Range(0.01, 1.00, ErrorMessage = "Please enter a positive number in range of 0.01 to 1.00")]
    public Double TargetYield { get; set; }

    [Timestamp]
    public Byte[] Timestamp { get; set; }
}

来自控制器的代码:

// Saves changes to the Line
    [HttpPost]
    public ActionResult Edit(Line line)
    {
        if (ModelState.IsValid)
        {
            repository.SaveLine(line);
            TempData["message"] = string.Format("{0} has been saved", line.Name);
            return RedirectToAction("Index");
        }
        else
        {
            // return to lines list if there is something wrong with the data
            return View(line);
        }
    }

来自实体框架存储库类的代码(这部分代码尚未完成,在发生并发的那一刻,它应该只是用数据库中的时间戳替换时间戳并再次保存):

    // Save changes to the line or create new one if not exists
    public void SaveLine(Line line)
    {
        // Checking if line with the same name already exists

        //Line found = Lines.FirstOrDefault(l => l.Name == line.Name);
        string found = Lines
            .Select(l => l.Name)
            .Where( n => n == line.Name)
            .SingleOrDefault();

        if (found == null)
        {
            context.Lines.Add(line);
        }
        else
        {
            context.Entry(line).State = System.Data.EntityState.Modified;
        }

        //context.SaveChanges();

        try
        {
            context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            var entry = ex.Entries.Single();
            var dbvalues = (Line)entry.GetDatabaseValues().ToObject();
            line.Timestamp = dbvalues.Timestamp;
            context.SaveChanges();
        }

    }

当我仅在一个选项卡中运行应用程序并尝试编辑线实体时,我收到此错误:

存储更新、插入或删除语句影响了意外数量的行 (0)。自加载实体后,实体可能已被修改或删除。刷新 ObjectStateManager 条目。

我已经调试并检查了时间戳值,它为空。但在数据库中是 0x0000000000000814。当在下一步中时间戳被替换为数据库中的时间戳并尝试再次保存时,它会引发相同的异常。

我不知道我在哪里犯了错误,非常感谢任何帮助

对不起我的英语。谢谢

4

3 回答 3

1

您需要将时间戳写到视图中,以确保它返回到您的实体中。

Html.HiddenFor(o=>o.Timestamp)

于 2013-04-14T22:36:04.873 回答
0

它在我运行单个应用程序实例时起作用,但是当我运行其中两个来测试并发性时。我得到了我已经处理并用数据库中的时间戳替换时间戳的异常,但即使两个时间戳相同,也会再次引发相同的异常:从即时窗口:

?line.Timestamp
{byte[8]}
[0]: 0
[1]: 0
[2]: 0
[3]: 0
[4]: 0
[5]: 0
[6]: 70
[7]: 81
?dbValues.Timestamp
{byte[8]}
[0]: 0
[1]: 0
[2]: 0
[3]: 0
[4]: 0
[5]: 0
[6]: 70
[7]: 81

这是为什么?它不仅应该在时间戳不同时引发异常吗?

于 2013-04-15T08:24:13.520 回答
0

已解决:看起来当我尝试在代码中再次保存时,它实际上仍然持有带有旧时间戳的旧对象。我已将 try catch 语句移至控制器并更改为替换时间戳并在并发发生时返回编辑视图。现在,当用户再次按下保存时,不会抛出异常并保存数据。

于 2013-04-15T12:59:00.267 回答