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

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

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

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

введите здесь описание изображения

Следующая диаграмма EDMX выглядит следующим образом:

Диаграмма 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();

person anar khalilov    schedule 13.01.2014    source источник
comment
Вы пытались установить xxx.UpdatedDate = DateTime.Now; ПОСЛЕ выполнения инструкции _dbContext.ObjectStateManager.ChangeObjectState... внутри else? Итак, переустановить его при обновлении? Попробуйте это и посмотрите, решит ли это вашу проблему. Если это сработает, дайте мне знать, и я опубликую ответ.   -  person Belogix    schedule 13.01.2014
comment
Могу я взглянуть на вашу модель?   -  person Rajshekar Reddy    schedule 13.01.2014
comment
@Belogix, позвольте мне попробовать, я отвечу как можно скорее.   -  person anar khalilov    schedule 13.01.2014
comment
@Reddy, я предоставил схему модели. Вам нужно что-то конкретное?   -  person anar khalilov    schedule 13.01.2014
comment
@Belogix, к сожалению, ничего не изменилось.   -  person anar khalilov    schedule 13.01.2014


Ответы (3)


UpdatedDate не допускает пустых значений. Сделайте его столбцом с нулевым значением в вашей базе данных.

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

person kvothe    schedule 13.01.2014
comment
Он также должен сделать его обнуляемым в модели, чтобы отразить базу данных. - person scheien; 13.01.2014
comment
UpdateDate специально не является полем, допускающим значение NULL. Он устанавливается как для вставленных, так и для обновленных записей. - person anar khalilov; 13.01.2014
comment
Вы редактировали код. Ваша предыдущая версия будет ошибкой, если она не может быть нулевой. Теперь он должен работать нормально. - person kvothe; 13.01.2014
comment
@AmarDuplantier, я забыл упомянуть об этом. Раньше было так, как сейчас, потом я изменил его, чтобы проверить, будет ли он работать, и забыл вернуться к исходной версии. Извините за введение в заблуждение. Это все еще не работает таким образом. - person anar khalilov; 13.01.2014

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

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

person JulyOrdinary    schedule 13.01.2014
comment
Я передаю DateTime.Now, который не может принимать значение NULL. - person anar khalilov; 13.01.2014

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

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

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

person John Zumbrum    schedule 15.01.2014
comment
Да, эта ошибка возникает только при попытке обновиться и это очень расстраивает. Я применил ваше решение как к гостевой, так и к домашней командам, и теперь я получаю эту ошибку: объект с таким же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом. Несмотря на то, что я отсоединил существующие сущности. Для дальнейшего изучения, пожалуйста, ознакомьтесь с частью вопроса UPDATE 2. - person anar khalilov; 16.01.2014