问题
I have spent nearly seven hours to figure this out and couldn't come up with a solution. So here am I, sharing this problem with you.
Please note that the following example is a simplification and subset of my original project. I tried to simplify it as much as possible for you.
To start, I have two business models:
The following EDMX diagram is as follows:
I am using MVC 4 and I have a simple page where you can enter home and away team names respectively and a save button to save these teams and the match:
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>
Controller
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);
}
}
}
As you can see inside the controller, the entered team name is compared to those in the database. If one exists, it is to be updated; else inserted. There are no problems with inserts but when an existing team name is entered inside a textbox, I get the following error message:
Cannot insert the value NULL into column 'UpdatedDate', table 'TestEF.dbo.Teams'; column does not allow nulls. INSERT fails. The statement has been terminated.
I get this error even though inside the controller, I explicitly set the UpdateDate for records that need to be updated and set its state to Modified. However the error message says as if UpdateDate field was not set. I debugged and made sure the fields are updated correctly but in SQL Profiler UpdateDate is not set. I am very confused.
I can share the full source code if needed.
UPDATE I suspect it has something to do with Attach/Detach but I am not sure.
UPDATE 2 I have simplified the code to see whether it works and it does. Then why does the original code not work?
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();
回答1:
UpdatedDate
does not allow nulls. Make it a nullable column in your database.
And also in your EDMX as scheien mentioned in the comment.
回答2:
Your schema in EF indicates that Null value is not allowed to be entered while adding/Inserting or Updating.
Make sure you are passing the correct non nullable value. Also you can change the schema of the table and update the model, so that null can be entered.
回答3:
Set a breakpoint here: awayTeam.UpdatedDate = DateTime.Now;
Then when you run it you can tell if it's pointing to the existing team or not.
I'm pretty certain that the issue is when you are trying to do an update. In that case you haven't detached your original object, instead you're trying to reassign. Give it a try to detach your existingAwayTeam, and then attach your matchData.AwayTeam, mark it as modified, and try saving it.
来源:https://stackoverflow.com/questions/21088398/cannot-update-entity-framework-model