【问题标题】:Strongly-Typed ASP.NET MVC with ADO.NET Entity Framework [closed]具有 ADO.NET 实体框架的强类型 ASP.NET MVC [关闭]
【发布时间】:2013-08-06 18:41:49
【问题描述】:

经过几天的努力,我终于完成了这项工作。

我有一个简单的人员和部门数据库:

ADO.NET Entity Framework Entity Data Model diagram with Department and Person objects http://img39.imageshack.us/img39/1368/edmxdepartmentperson.gif

我可以将强类型的 ASP.NET MVC 视图用于引用/导航属性!查看部门列表...

ASP.NET MVC with DropDownList http://img11.imageshack.us/img11/7619/dropdownlistdepartment.gif

我的个人/编辑视图的一部分:

<% using (Html.BeginForm()) {%>
    <%= Html.Hidden("Id", Model.Id) %>
    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name", Model.Name) %>
        </p>
        <p>
            <label for="DepartmentId">Department:</label>
            <%= Html.DropDownList("DepartmentId", new SelectList((IEnumerable)ViewData["Departments"], "Id", "Name"))%>
        </p>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
<% } %>

我的 Person 控制器的一部分:

//
// GET: /Person/Edit/5

public ActionResult Edit(Guid id)
{
    ViewData["Departments"] = ctx.Department;
    Person model = (from Person p in ctx.Person
                    where p.Id == id
                    select p).FirstOrDefault();
    return View(model);
}

//
// POST: /Person/Edit

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Person model)
{
    ctx.AttachUpdated(model);  //extension
    ctx.SaveChanges();
    return RedirectToAction("Index");
}

为了让它工作,我用一个新的 DepartmentId 属性扩展了 Person EntityObject。

using System;
using System.Data;
using System.Data.Objects.DataClasses;

namespace ProjectName.Models
{
    public partial class Person : EntityObject
    {
        public Guid DepartmentId
        {
            get
            {
                try
                {
                    return (Guid)this.DepartmentReference.EntityKey.EntityKeyValues[0].Value;
                }
                catch
                {
                    return Guid.Empty;
                }
            }
            set
            {
                this.DepartmentReference.EntityKey = new EntityKey("JunkEntities.Department", "Id", value);
            }
        }
    }
}

我使用新的 AttachUpdated 和 ApplyReferencePropertyChanges 方法扩展了实体框架 ObjectContext:

using System;
using System.Data;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

public static class EntityFrameworkExtensionMethods
{

    public static void AttachUpdated(this ObjectContext ctx, EntityObject objectDetached)
    {
        if (objectDetached.EntityKey == null)
        {
            String entitySetName = ctx.DefaultContainerName + "." + objectDetached.GetType().Name;
            Guid objectId = (Guid)objectDetached.GetType().GetProperty("Id").GetValue(objectDetached, null);
            objectDetached.EntityKey = new System.Data.EntityKey(entitySetName, "Id", objectId);
        }
        if (objectDetached.EntityState == EntityState.Detached)
        {
            object currentEntityInDb = null;
            if (ctx.TryGetObjectByKey(objectDetached.EntityKey, out currentEntityInDb))
            {
                ctx.ApplyPropertyChanges(objectDetached.EntityKey.EntitySetName, objectDetached);
                ctx.ApplyReferencePropertyChanges((IEntityWithRelationships)objectDetached,
                                                  (IEntityWithRelationships)currentEntityInDb);  //extension
            }
            else
            {
                throw new ObjectNotFoundException();
            }
        }
    }

    public static void ApplyReferencePropertyChanges(this ObjectContext ctx, IEntityWithRelationships newEntity, IEntityWithRelationships oldEntity)
    {
        foreach (var relatedEnd in oldEntity.RelationshipManager.GetAllRelatedEnds())
        {
            var oldRef = relatedEnd as EntityReference;
            if (oldRef != null)
            {
                var newRef = newEntity.RelationshipManager.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName) as EntityReference;
                oldRef.EntityKey = newRef.EntityKey;
            }
        }
    }

}

我只是想在这里记录我的进步。请提出改进​​建议。


谢谢:

【问题讨论】:

  • 干得好,但不幸的是 stackoverflow.com 不是您记录进度的地方。我投票结束:“不是一个真正的问题”。
  • 这里绑定person对象时不需要排除id属性吗:public ActionResult Edit(Guid id, Person Model)?
  • 啊,我错过了关于“建议改进”的部分。我说,让它活下去吧。
  • 如果我在这里输入一个伪造的 ID 怎么办:public ActionResult Edit(Guid id)?您不会检查是否存在具有该 ID 的人,如果不存在则不会向用户显示错误。
  • 就像说我很高兴这被留下来“活着”,并且 stackoverflow 应该可以灵活地让人们记录这样的东西。有几个原因。 1)。它在搜索中排名很高,让其他开发人员从中学习。即社区利益。 2)像这样的支持材料可以用于其他问题的答案。

标签: asp.net-mvc entity-framework ado.net


【解决方案1】:

我已经开始使用 ASP.NET MVC,这就是我遇到这个线程的原因,所以我不确定你是否还在检查改进。

我不喜欢将新属性添加到实体框架上的部分类的想法,因为它不允许进行太多更改。 尝试像这样标记您的部门下拉菜单“Department.Id”

<p>
    <label for="Department.Id">Department:</label>
<%= Html.DropDownList("Department.Id", new SelectList((IEnumerable)ViewData["Departments"], "Id", "Name"))%>
</p>

MVC 框架的 ModelBinding 将获取该值并将其应用于“部门”导航属性的“Id”属性。我发现 Department 的其他值都是空的,但这并不重要。现在您可以检索正确的部门实体并将其应用于在模型中创建的新人员实体的部门导航属性绑定到您的操作参数,例如:

newPerson.Department = ctx.Department.First(d => d.DepartmentId == newPerson.Department.Id);

通过这种方式,您根本不需要更新您的实体以获得它应该具有的属性。

【讨论】:

  • 又好又干净! Zack,您还可以在控制器上设置 EntityKey 编辑方法:newPerson.DepartmentReference.EntityKey = new EntityKey("YourEntities.Department","DepartmentId", int.Parse(Request.Form["DepartmentId"]));
【解决方案2】:

改进您的编辑控件,以便它处理引发的异常并重新显示用户迄今为止输入的输入。我敢肯定你即将;)

更新您的视图以拥有验证器:

<label for="Name">Name:</label>
<%= Html.TextBox("Name", Model.Name) %>
<%= Html.ValidationMessage("Name", "*") %>

然后在您的编辑中使用它们:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Person Model)
{
    try
    {
       ctx.AttachUpdated(Model);  //extension
       ctx.SaveChanges();
       return RedirectToAction("Index");
    }
    catch
    {
        foreach (var err in Model.Errors)
          ModelState.AddModelError(err.PropertyName, err.ErrorMessage)

        return View(Model);
    }
}

【讨论】:

  • "'....Person' 不包含 'Errors' 的定义,并且找不到接受类型为 '....Person' 的第一个参数的扩展方法 'Errors'(是您缺少 using 指令或程序集引用?)"
  • 这取决于您使用的框架。 Lightspeed 和 Linq2Sql 为您提供每个实体的 Errors 属性。如果您手动构建实体而不是使用 ORM,则需要将该属性构建到 Person 的部分类中。
  • 类似于本文中的清单 3 和 4:asp.net/Learn/mvc/tutorial-16-cs.aspx
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-18
  • 2010-09-08
  • 2010-09-06
  • 2015-11-29
  • 2010-09-27
  • 2016-07-19
  • 1970-01-01
相关资源
最近更新 更多