繁体   English   中英

使用MVC 4和Entity Framework更新相关数据吗?

[英]Updating related data using MVC 4 and Entity Framework?

因此,我在保存包含相关实体的数据时遇到了问题,当我将其保存时会创建一个新的关系空白。

例:

实体:

public class Project
{
    public int Id { get; set; }
    public int Code{ get; set; }
    public string Description{ get; set; }

    public virtual Client Client { get; set; }
}


public class Client
{
    public int Id { get; set; }
    public int Code { get; set; }
    public string Name { get; set; }
}

控制器GET:

public ActionResult Create()
{
    PopulateDropDownClienteList(String.Empty); //Returns to ViewBag to create a combobox .in view
    return View();
}

风景:

 @Html.DropDownListFor(m => m.Client.Id, new SelectList(ViewBag.Client_Id, "Id", "Name"), new { Name = "Client.Id" });

控制器POST:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(string command, Project project)
    {
        try
        {
            if (ModelState.IsValid)
            {
                projectRepository = new ProjeRepository();
                Project pro = projectRepository.ReturnByCode(project.Code);

                if (pro == null)
                    projectRepository.Save(project);
                else
                    projectRepository.Update(project);

                PopulateDropDownClienteList(String.Empty);

                Return View();

            }
            else
            {
                return View(project);
            }
        }
        catch (Exception ex)
        {
            return View();
        }
    }

因此,当我保存数据时,客户端未与项目关联。 只是创建一个新的空白客户端。

您在这里遇到了很多问题,所以让我分解一下。

首先, 永远不要捕获Exception (至少不要再次抛出它)。 使用try...catch块有两个非常重要的事情:您只应将代码包装在您期望发生异常的位置(而不是您在此处所做的几乎整个方法),并且只应捕获特定的异常期待(不是基本类型Exception )。 当您捕获Exception ,将捕获可能从您的代码生成的所有异常,并且在这种情况下,将其简单地丢弃,这意味着您真的将永远不知道此代码是否可以正常工作。

其次,您可以使用一种很好的方法来生成选项的下拉列表,但不要将用户的选择存储在有意义的位置。 要了解原因,您需要停下来思考一下这里发生的事情。 HTML select元素具有字符串值和字符串文本或标签组件。 它不支持来回传递完整对象。 我看不到您的PopulateDropDownClienteList方法做什么,但是它应该做的是创建一个IEnumerable<SelectListItem> ,其中每个项目的Text属性设置为想要显示的内容,而Value属性设置为Client PK。 但是,一旦有了它,就需要在Project上添加一些属性以回发到该属性。 您的虚拟Client无法使用,因为它需要一个完整的Client实例,而您的表单将永远不会有该实例。 因此,您有两种选择:

  1. 实现视图模型以馈送到视图(并在帖子中接受)。 在该视图模型中,除了所有其他可编辑字段外,还将包括ClientId类的类型,它将是一个int类型,并将其绑定到下拉列表中。 使用post方法后,将所有发布的值映射到您的项目实例,然后使用ClientId从数据库中查找客户端。 然后,将结果客户设置为Client属性的值,并照常保存。

  2. 您会稍微更改数据库。 当您只指定一个虚拟时,Entity Framework会巧妙地创建一个外键和一列以在后台为您保留该关系。 太好了,但是在这种情况下,实际上您需要访问该外键列,这很麻烦。 解决该问题的方法是显式定义一个属性以在模型上保留该关系,并告诉Entity Framework使用该属性,而不是创建自己的属性。

     [ForeignKey("Client")] public int ClientId { get; set; } public virtual Client Client { get; set; } 

    这样,您现在可以直接使用ClientId而不必担心填写Client 您再次将下拉列表绑定到ClientId ,但是现在,您无需从数据库中显式查找客户端。 Entity Framework只会将ClientId正确保存到数据库中,然后在以后再次查找项目时基于该Client ClientId还原Client

您的项目保存代码不是在更新实体,而是一直在添加新的实体。

您应该具有与以下理由类似的更新逻辑-

要添加新的FK条目并将其与父记录相关联-

var entity = entities.Students.Where(p => p.Id == "2").First();
entity.StudentContact = new StudentContact() { Contact = "xyz", Id = "2" };

entities.Students.Attach(entity);
var entry = entities.Entry(entity);
// other changed properties
entities.SaveChanges();

要使用新的详细信息更新FK记录-

var entity = entities.Students.FirstOrDefault();
entity.StudentContact.Contact = "ABC";

entities.Students.Attach(entity);
var entry = entities.Entry(entity);
entry.Property(e => e.StudentContact.Contact).IsModified = true;
// other changed properties
entities.SaveChanges();

上面的代码,我有一个Student记录,它与StudentContacts有FK关系。 我更新了学生的联系信息,然后使用ATTACH将其更新到数据库。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM