ASP.Net MVC 3时间戳为空

时间:2013-04-14 22:10:21

标签: asp.net-mvc-3 concurrency timestamp

我构建了我的第一个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; }
}
来自Controller的

代码:

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

来自Entity Framework存储库类的代码(这部分代码尚未竞争,在发生并发时它应该只用db中的那个替换时间戳并再次保存):

    // 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。在下一步中,时间戳被替换为数据库中的时间戳并尝试再次保存时,会抛出相同的异常。

我不知道我犯了什么错误,非常感谢任何帮助

对不起我的英语。 谢谢

3 个答案:

答案 0 :(得分:1)

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

Html.HiddenFor(O => o.Timestamp)

答案 1 :(得分:0)

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

?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

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

答案 2 :(得分:0)

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