Не удается обновить модель фреймворка сущности

Я потратил почти семь часов, чтобы понять это, и не смог найти решение. Итак, вот я, разделяя эту проблему с вами.

Обратите внимание, что следующий пример - это упрощение и подмножество моего первоначального проекта. Я попытался упростить его как можно больше.

Для начала у меня две бизнес-модели:

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 в столбец "Обновлено", таблица 'TestEF.dbo.Teams'; столбец не допускает нулей. INSERT терпит неудачу. утверждение завершено.

Я получаю эту ошибку, хотя внутри контроллера я явно устанавливаю UpdateDate для записей, которые необходимо обновить, и установите его состояние в Модифицировано. Однако в сообщении об ошибке указано, что поле UpdateDate не установлено. Я отлаживал и убедился, что поля обновлены правильно, но в SQL Profiler UpdateDate не установлен. Я очень смущен.

При необходимости я могу предоставить полный исходный код.

UPDATE Я подозреваю, что это имеет какое-то отношение к Attach/Detach, но я не уверен.

ОБНОВЛЕНИЕ 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();

Ответы

Ответ 1

UpdatedDate не разрешает null. Сделайте его нулевым столбцом в своей базе данных.

А также в вашем EDMX как scheien, упомянутом в комментарии.

Ответ 2

Ваша схема в EF указывает, что при добавлении/вставке или обновлении значение Null не допускается.

Убедитесь, что вы передаете правильное значение, отличное от нуля. Также вы можете изменить схему таблицы и обновить модель, чтобы можно было ввести нуль.

Ответ 3

Задайте точку останова здесь: awayTeam.UpdatedDate = DateTime.Now;

Затем, когда вы запустите его, вы можете сказать, указывает ли он на существующую команду или нет.

Я уверен, что проблема в том, что вы пытаетесь сделать обновление. В этом случае вы не отделили исходный объект, вместо этого вы пытаетесь переназначить. Попробуйте отсоединить ваш существующий AwayTeam, а затем присоедините свой matchData.AwayTeam, пометьте его как измененный и попробуйте сохранить его.