无法更新实体框架模型 [英] Cannot update entity framework model

查看:165
本文介绍了无法更新实体框架模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我花了将近七个小时来解决这个问题,无法提出解决方案。所以这里是我,与你分享这个问题。



请注意,以下示例是我原始项目的简化和子集。我试图尽可能简化它。



要开始,我有两种商业模式:





以下EDMX图如下:





我正在使用MVC 4,我有一个简单的页面,您可以分别输入家庭和家庭名称以及保存按钮来保存这些团队和比赛:





CSHTML

  @model TestEF.Data.Match 
@ {
Layout = null;
}
<!DOCTYPE html>
< html>
< head>
< meta name =viewportcontent =width = device-width/>
< title> NewMatch< / title>
< / head>
< body>
< div>
状态:@ 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 =submitvalue =保存/>
}
< / 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);
团队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 =成功;

返回PartialView(matchData);
}
else
{
ViewBag.Status =无效输入。

返回PartialView(matchData);
}
}
catch(Exception ex)
{
ViewBag.Status =Error:+(ex.InnerException!= null?ex.InnerException.Message :ex.Message);

返回PartialView(matchData);
}
}
}

正如你可以看到控制器,输入的团队名称与数据库中的人员进行比较。如果存在,则进行更新;否则插入。插入没有任何问题,但是当在文本框内输入现有的团队名称时,我会收到以下错误消息:


无法插入将值NULL值改为列UpdatedDate,表
'TestEF.dbo.Teams';列不允许为空。 INSERT失败。
语句已被终止。


即使在控制器内部我也收到这个错误,我明确地设置UpdateDate进行记录需要更新并将其状态设置为修改。但是,错误消息说如果UpdateDate字段未设置。我调试并确保字段正确更新,但在SQL Profiler UpdateDate未设置。我很困惑。



如果需要,我可以共享完整的源代码。



更新我怀疑它与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;

匹配newMatch = new Match()
{
HomeTeam = homeTeam,
AwayTeam = awayTeam,
UpdateDate = DateTime.Now
} ;

_dbContext.AddToMatches(newMatch);
_dbContext.SaveChanges();


解决方案

在此设置断点:awayTeam.UpdatedDate = DateTime。现在;



然后当你运行它可以告诉它是否指向现有的团队。



我很确定问题是当您尝试更新时。在这种情况下,您没有分离原始对象,而是尝试重新分配。尝试分离您现有的AwayTeam,然后附加您的matchData.AwayTeam,将其标记为已修改,然后尝试保存。


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();

解决方案

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.

这篇关于无法更新实体框架模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆