programing

Entity Framework에서 업데이트시 속성 제외

nasanasas 2020. 10. 29. 08:14
반응형

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
}

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

In case you want to use it just in some scenarios and avoid its "nullification" in the case above, you can try to:

  • Hide the parameter in the view with HiddenFor:

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

This will make your original value to be kept unmodified and passed back to the controller.

Load again your object in the controller from your DBSet and run this method. You can specify both a white list and a blacklist of parameters that shall or shall not be update.

참고URL : https://stackoverflow.com/questions/12661881/exclude-property-on-update-in-entity-framework

반응형