我花了将近7个小时来弄明白这一点,并不能提出解决方案。所以,我在这里,与你分享这个问题。无法更新实体框架模型
请注意,以下示例是我原始项目的简化和子集。我尽可能为你简化它。
开始,我有两种商业模式:
下EDMX图如下:
我使用MVC 4,我有一个简单的页面您可以分别输入主客场球队名称和保存按钮以保存这些球队和比赛:
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();
您是否尝试设置'xxx.UpdatedDate = DateTime.Now;里面的''else' ** **后做'_dbContext.ObjectStateManager.ChangeObjectState ...'声明?那么,如果更新,重新设置它?试试看看它是否能解决你的问题。如果它工作让我知道,我会发布答案。 – Belogix
我可以看看你的模特吗? –
@Belogix,让我试试看,我会尽快回复。 –