0

假设我有 3 个模型:

[Table("UserProfile")]
public class UserProfile //this is a standard class from MVC4 Internet template
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
}

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }

    public int UserProfileId { get; set; }
    [ForeignKey("UserProfileId")]
    public virtual UserProfile UserProfile { get; set; }
}

现在,我正在尝试编辑帖子

        [HttpPost]
        public ActionResult Edit(Post post)
        {

            post.UserProfileId = context.UserProfile.Where(p => p.UserName == User.Identity.Name).Select(p => p.UserId).FirstOrDefault();

            //I have to populate post.Category manually 
            //post.Category = context.Category.Where(p => p.Id == post.CategoryId).Select(p => p).FirstOrDefault();



            if (ModelState.IsValid)
            {
                context.Entry(post.Category).State = EntityState.Modified; //Exception
                context.Entry(post.UserProfile).State = EntityState.Modified;
                context.Entry(post).State = EntityState.Modified;
                context.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(post);
        }

我得到了ArgumentNullException。快速查看调试,我可以看出我的Categorynull,尽管CategoryId设置为正确的值。

注释掉的,看起来很讨厌的技巧解决了这个问题,但我想它根本不应该存在。所以问题是如何正确解决它

我会说它与 EF 延迟加载有关,因为我有非常相似的代码来添加Post并且在调试中有相同的场景:正确CategoryIdCategorynull并且尽管 EF 自动解决了Post <-> Category依赖,我不必使用任何额外的技巧。在编辑方法上,EF 有一些问题,但我无法弄清楚我做错了什么。

4

1 回答 1

1

这是按预期工作的。您的Post对象未附加到上下文,因此没有理由进行任何延迟加载。这是完整的代码吗?我不明白为什么你需要设置 CategoryModified因为你实际上并没有改变它的任何内容。

无论如何,我建议您从数据库中查询现有帖子并分配您要让用户修改的相关字段,如下所示:

[HttpPost]
public ActionResult Edit(Post post)
{
    var existingPost = context.Posts
        .Where(p => p.Id == post.Id)
        .SingleOrDetault();

    if (existingPost == null)
        throw new HttpException(); // Or whatever you wanna do, since the user send you a bad post ID

    if (ModelState.IsValid)
    {
        // Now assign the values the user is allowed to change
        existingPost.SomeProperty = post.SomeProperty;
        context.SaveChanges();

        return RedirectToAction("Index");
    }

    return View(post);
}

这样,您还可以确保用户尝试编辑的帖子确实存在。仅仅因为您收到了一些操作参数,并不意味着它们是有效的或帖子的 ID 是真实的。例如,一些不怀好意的用户可能决定编辑他不允许编辑的帖子。你需要检查这种事情。

更新

附带说明一下,您还可以避免手动查询当前用户的 ID。如果您正在使用Simple Membership,您可以使用WebSecurity.CurrentUserId.
如果你正在使用Forms Authentication,你可以做到Membership.GetUser().ProviderUserKey

于 2013-04-02T19:04:48.723 回答