88

MVC でモデルを更新するときにプロパティを変更しないようにマークする適切な方法を探していました。

たとえば、次の小さなモデルを見てみましょう。

class Model
{
    [Key]
    public Guid Id {get; set;}
    public Guid Token {get; set;}

    //... lots of properties here ...
}

次に、MVC が作成する編集メソッドは次のようになります。

[HttpPost]
public ActionResult Edit(Model model)
{
    if (ModelState.IsValid)
    {
        db.Entry(model).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(model);
}

ビューにトークンが含まれていない場合、その編集によって無効になります。

私はこのようなものを探しています:

db.Entry(model).State = EntityState.Modified;
db.Entry(model).Property(x => x.Token).State = PropertyState.Unmodified;
db.SaveChanges();

これまでに見つけた最善の方法は、包括的で、含めたいすべてのプロパティを手動で設定することですが、実際には除外するプロパティだけを言いたいと思います。

4

6 に答える 6

10

更新するプロパティのセットが制限された新しいモデルを作成します。

つまり、エンティティ モデルが次の場合:

public class User
{
    public int Id {get;set;}
    public string Name {get;set;}
    public bool Enabled {get;set;}
}

ユーザーが名前を変更できるようにするカスタム ビュー モデルを作成できますが、有効フラグは変更できません。

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

データベースの更新を行う場合は、次のようにします。

YourUpdateMethod(UserProfileModel model)
{
    using(YourContext ctx = new YourContext())
    { 
        User user = new User { Id = model.Id } ;   /// stub model, only has Id
        ctx.Users.Attach(user); /// track your stub model
        ctx.Entry(user).CurrentValues.SetValues(model); /// reflection
        ctx.SaveChanges();
    }
}

このメソッドを呼び出すと、Name は更新されますが、Enabled プロパティは変更されません。単純なモデルを使用しましたが、使用方法がイメージできると思います。

于 2012-09-30T15:26:32.773 に答える
3

共有するエンティティのプロパティを編集する簡単な方法を作成しました。このコードは、エンティティの Name プロパティと Family プロパティを編集します。

    public void EditProfileInfo(ProfileInfo profileInfo)
    {
        using (var context = new TestContext())
        {
            context.EditEntity(profileInfo, TypeOfEditEntityProperty.Take, nameof(profileInfo.Name), nameof(profileInfo.Family));
        }
    }

そして、このコードは、エンティティの Name プロパティと Family プロパティの編集を無視し、別のプロパティを編集します。

    public void EditProfileInfo(ProfileInfo profileInfo)
    {
        using (var context = new TestContext())
        {
            context.EditEntity(profileInfo, TypeOfEditEntityProperty.Ignore, nameof(profileInfo.Name), nameof(profileInfo.Family));
        }
    }

この拡張機能を使用します:

public static void EditEntity<TEntity>(this DbContext context, TEntity entity, TypeOfEditEntityProperty typeOfEditEntityProperty, params string[] properties)
   where TEntity : class
{
    var find = context.Set<TEntity>().Find(entity.GetType().GetProperty("Id").GetValue(entity, null));
    if (find == null)
        throw new Exception("id not found in database");
    if (typeOfEditEntityProperty == TypeOfEditEntityProperty.Ignore)
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            if (properties.Contains(item.Name))
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    else if (typeOfEditEntityProperty == TypeOfEditEntityProperty.Take)
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            if (!properties.Contains(item.Name))
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    else
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    context.SaveChanges();
}

public enum TypeOfEditEntityProperty
{
    Ignore,
    Take
}
于 2018-04-08T07:07:39.503 に答える
1

アプリケーションでプロパティを使用しない場合は、モデルから削除するだけなので、場合によってはプロパティを変更したくないと思います。

一部のシナリオでのみ使用し、上記の場合の「無効化」を回避したい場合は、次のことを試すことができます。

  • HiddenFor を使用してビュー内のパラメーターを非表示にします。

    @Html.HiddenFor(m => m.Token)

これにより、元の値が変更されずに保持され、コントローラーに戻されます。

からコントローラにオブジェクトを再度ロードし、DBSetこのメソッドを実行します。更新する、または更新しないパラメーターのホワイト リストとブラックリストの両方を指定できます。

于 2012-10-01T08:47:58.637 に答える