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を取得しています。デバッグを簡単に調べると、CategoryId が適切な値に設定されていても、Categorynullあることがわかります。

コメントアウトされた、見栄えの悪いトリックがこの問題を解決しますが、まったく存在しないはずです。問題は、それを適切に解決する方法です。

Postを追加するための非常によく似たコードがあり、デバッグには同じシーンがあります。適切なCategoryIdCategorynullであるにもかかわらず、EF はそのPost <-> Category依存関係を自動的に解決します。追加のトリックを使用する必要はありません。編集方法では、EF に問題がありますが、何が間違っているのかわかりません。

4

1 に答える 1

1

これは意図したとおりに機能しています。Postオブジェクトは Context にアタッチされていないため、遅延読み込みを行う理由はありません。これは完全なコードですか?Modified実際には何も変更していないので、Category を as に設定する必要がある理由がわかりません。

とにかく、データベースから既存の投稿を照会し、ユーザーが変更できるようにする関連フィールドを次のように割り当てることをお勧めします。

[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は、現在のユーザーの ID を取得できますWebSecurity.CurrentUserId
を使用している場合は、Forms Authentication実行できますMembership.GetUser().ProviderUserKey

于 2013-04-02T19:04:48.723 に答える