Я потратил почти семь часов, чтобы понять это, и не смог найти решение. Итак, вот и я, делюсь с вами этой проблемой.
Обратите внимание, что следующий пример является упрощением и подмножеством моего исходного проекта. Я постарался максимально упростить для вас.
Для начала у меня есть две бизнес-модели:
Следующая диаграмма 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»; столбец не допускает пустых значений. ВСТАВИТЬ не удается. Заявление было прекращено.
Я получаю эту ошибку, хотя внутри контроллера я явно устанавливаю UpdateDate для записей, которые необходимо обновить, и устанавливаю их состояние на Modified. Однако в сообщении об ошибке говорится, что поле UpdateDate не было установлено. Я отладил и убедился, что поля обновлены правильно, но в SQL Profiler UpdateDate не установлен. Я очень смущен.
Я могу поделиться полным исходным кодом, если это необходимо.
ОБНОВЛЕНИЕ Я подозреваю, что это как-то связано с присоединением/отсоединением, но я не уверен.
ОБНОВЛЕНИЕ 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;
ПОСЛЕ выполнения инструкции_dbContext.ObjectStateManager.ChangeObjectState...
внутриelse
? Итак, переустановить его при обновлении? Попробуйте это и посмотрите, решит ли это вашу проблему. Если это сработает, дайте мне знать, и я опубликую ответ. - person Belogix   schedule 13.01.2014