2014-01-13 216 views
0

我花了将近7个小时来弄明白这一点,并不能提出解决方案。所以,我在这里,与你分享这个问题。无法更新实体框架模型

请注意,以下示例是我原始项目的简化和子集。我尽可能为你简化它。

开始,我有两种商业模式:

enter image description here

下EDMX图如下:

EDMX Diagram

我使用MVC 4,我有一个简单的页面您可以分别输入主客场球队名称和保存按钮以保存这些球队和比赛:

New match entry page

CSHTML

@model TestEF.Data.Match 
@{ 
    Layout = null; 
} 
<!DOCTYPE html> 
<html> 
<head> 
    <meta name="viewport" content="width=device-width" /> 
    <title>NewMatch</title> 
</head> 
<body> 
    <div> 
     Status: @ViewBag.Status 
    </div> 
    <div id="NewMatchFormContainer"> 
     @using (Ajax.BeginForm(new AjaxOptions() { Url = "/Match/NewMatch", UpdateTargetId = "NewMatchFormContainer" })) 
     { 
      @Html.ValidationSummary(false) 

      @Html.TextBox("HomeTeamName", "", new { Name = "HomeTeam.TeamName" }); 
      @Html.TextBox("AwayTeamName", "", new { Name = "AwayTeam.TeamName" }); 

      <input type="submit" value="Save" /> 
     } 
    </div> 
</body> 
</html> 

控制器

public class MatchController : Controller 
{ 
    TestEFEntities _dbContext = new TestEFEntities(); 

    public ActionResult Index() 
    { 
     return View(); 
    } 

    public ActionResult NewMatch() 
    { 
     return View(); 
    } 

    [HttpPost] 
    public ActionResult NewMatch(Match matchData) 
    { 
     try 
     { 
      if (ModelState.IsValid) 
      { 
       using (TransactionScope ts = new TransactionScope()) 
       { 
        string homeTeamName = matchData.HomeTeam.TeamName; 
        Team existingHomeTeam = _dbContext.Teams.SingleOrDefault(i => i.TeamName == homeTeamName); 
        Team homeTeam = existingHomeTeam ?? matchData.HomeTeam; 
        homeTeam.UpdatedDate = DateTime.Now; 

        if (existingHomeTeam == null) 
        { 
         _dbContext.AddToTeams(homeTeam); 
        } 
        else 
        { 
         _dbContext.ObjectStateManager.ChangeObjectState(homeTeam, System.Data.EntityState.Modified); 
        } 

        string awayTeamName = matchData.AwayTeam.TeamName; 
        Team existingAwayTeam = _dbContext.Teams.SingleOrDefault(i => i.TeamName == awayTeamName); 
        Team awayTeam = existingAwayTeam ?? matchData.AwayTeam; 
        awayTeam.UpdatedDate = DateTime.Now; 

        if (existingAwayTeam == null) 
        { 
         _dbContext.AddToTeams(awayTeam); 
        } 
        else 
        { 
         _dbContext.ObjectStateManager.ChangeObjectState(awayTeam, System.Data.EntityState.Modified); 
        } 

        matchData.HomeTeam = homeTeam; 
        matchData.AwayTeam = awayTeam; 

        _dbContext.AddToMatches(matchData); 
        _dbContext.SaveChanges(); 

        ts.Complete(); 
       } 

       ViewBag.Status = "Success"; 

       return PartialView(matchData); 
      } 
      else 
      { 
       ViewBag.Status = "Invalid input."; 

       return PartialView(matchData); 
      } 
     } 
     catch (Exception ex) 
     { 
      ViewBag.Status = "Error: " + (ex.InnerException != null ? ex.InnerException.Message : ex.Message); 

      return PartialView(matchData); 
     } 
    } 
} 

,你可以在控制器内看到,输入队名相比,那些在数据库中。如果存在,它将被更新;其他插入。没有与刀片没有问题,但是当一个文本框里面输入一个现有的队名,我收到以下错误信息:

无法将NULL值插入列“UpdatedDate”,表 “TestEF.dbo.Teams “;列不允许有空值。 INSERT失败。 声明已被终止。

我得到即使控制器里面,我明确地设置UpdateDate对于需要进行更新,并设置其状态修改的记录此错误。但是,错误消息说,如果UpdateDate字段未设置。我调试并确保字段更新正确,但在SQL事件探查器UpdateDate未设置。我很困扰。

如果需要,我可以共享完整的源代码。

UPDATE我怀疑它与Attach/Detach有关系,但我不确定。

UPDATE 2我已简化了代码,以查看它是否有效并确实有效。那么为什么原始代码不起作用?

Team homeTeam = new Team() { TeamId = 1 }; 
Team awayTeam = new Team() { TeamId = 2 }; 

_dbContext.Teams.Attach(homeTeam); 
homeTeam.UpdatedDate = DateTime.Now; 

_dbContext.Teams.Attach(awayTeam); 
awayTeam.UpdatedDate = DateTime.Now; 

Match newMatch = new Match() 
{ 
    HomeTeam = homeTeam, 
    AwayTeam = awayTeam, 
    UpdateDate = DateTime.Now 
}; 

_dbContext.AddToMatches(newMatch); 
_dbContext.SaveChanges(); 
+0

您是否尝试设置'xxx.UpdatedDate = DateTime.Now;里面的''else' ** **后做'_dbContext.ObjectStateManager.ChangeObjectState ...'声明?那么,如果更新,重新设置它?试试看看它是否能解决你的问题。如果它工作让我知道,我会发布答案。 – Belogix

+0

我可以看看你的模特吗? –

+0

@Belogix,让我试试看,我会尽快回复。 –

回答

0

UpdatedDate不允许空值。将其设置为数据库中的空列。

而且还在您的EDMX中作为方案在评论中提到。

+0

他也应该让它在模型中可以为空,以反映数据库。 – scheien

+1

UpdateDate不是有意为空的字段。它被设置为插入和更新记录。 –

+0

您编辑了代码。如果它不是空的,你以前的版本会出错。现在它应该可以正常工作。 –

0

EF中的模式表示在添加/插入或更新时不允许输入空值。

请确保您传递了正确的非空值。 您也可以更改表格的模式并更新模型,以便输入null。

+0

我传递DateTime.Now这是一个不可为空的值。 –

0

在这里设置一个断点:awayTeam.UpdatedDate = DateTime.Now;

然后,当你运行它,你可以,如果它指向现有的团队或说不清。

我敢肯定,问题是,当你试图做一个更新。在这种情况下,您尚未分离出原始对象,而是尝试重新分配。尝试分离您的existingAwayTeam,然后附加您的matchData.AwayTeam,将其标记为已修改,然后尝试保存它。

+0

是的,只有在尝试更新时才会出现此错误,这非常令人沮丧。我将您的解决方案应用于客场球队和主队,现在我得到这个错误:“ObjectStateManager中已存在具有相同键的对象,ObjectStateManager无法使用同一个键跟踪多个对象。”尽管我分离了现有的实体。有关进一步调查,请查看问题的** UPDATE 2 **部分。 –