[c#] Entity Framework에서 업데이트시 속성 제외

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();

지금까지 내가 찾은 가장 좋은 방법은 포함하고 원하는 모든 속성을 손으로 설정하는 것이지만 실제로는 제외 할 속성 만 말하고 싶습니다.



답변

우리는 이렇게 사용할 수 있습니다

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

업데이트되지만 Token 속성은 없습니다.


답변

업데이트 할 속성 집합이 제한된 새 모델을 만듭니다.

즉, 엔티티 모델이 다음과 같은 경우 :

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 속성은 변경되지 않습니다. 나는 단순한 모델을 사용했지만 그것을 사용하는 방법을 그림으로 얻을 것이라고 생각합니다.


답변

EF Core에서이를 달성하는 방법을 찾는 모든 사람. 기본적으로 동일하지만 업데이트 할 모델을 추가 한 후에 IsModified가 있어야합니다.

db.Update(model);
db.Entry(model).Property(x => x.Token).IsModified = false;
db.SaveChanges();


답변

공유 할 엔티티의 속성을 쉽게 편집 할 수있는 방법을 만들었습니다. 이 코드는 엔티티의 이름 및 패밀리 속성을 편집합니다.

    public void EditProfileInfo(ProfileInfo profileInfo)
    {
        using (var context = new TestContext())
        {
            context.EditEntity(profileInfo, TypeOfEditEntityProperty.Take, nameof(profileInfo.Name), nameof(profileInfo.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
}


답변

응용 프로그램에서 사용하지 않을 경우 모델에서 제거하기 때문에 일부 경우에만 속성이 변경되는 것을 원하지 않는 것 같습니다.

일부 시나리오에서만 사용하고 위의 경우 “무효화”를 방지하려는 경우 다음을 시도 할 수 있습니다.

  • HiddenFor를 사용하여보기에서 매개 변수를 숨 깁니다.

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

이렇게하면 원래 값이 수정되지 않고 컨트롤러로 다시 전달됩니다.

컨트롤러에서 개체를 다시로드 DBSet하고이 메서드를 실행합니다. 업데이트하거나 업데이트하지 않을 매개 변수의 화이트리스트와 블랙리스트를 모두 지정할 수 있습니다.


답변