your programing

Entity Framework 5 레코드 업데이트

lovepro 2020. 9. 28. 09:51
반응형

Entity Framework 5 레코드 업데이트


ASP.NET MVC3 환경에서 Entity Framework 5 내에서 레코드를 편집 / 업데이트하는 다양한 방법을 탐색 해 왔지만 지금까지 필요한 모든 상자를 선택하지 않았습니다. 이유를 설명하겠습니다.

장단점을 언급 할 세 가지 방법을 찾았습니다.

방법 1-원본 레코드로드, 각 속성 업데이트

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

장점

  • 변경할 속성을 지정할 수 있습니다.
  • 뷰가 모든 속성을 포함 할 필요는 없습니다.

단점

  • 원본을로드 한 후 업데이트하기 위해 데이터베이스에 대한 2 x 쿼리

방법 2-원본 레코드로드, 변경된 값 설정

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

장점

  • 수정 된 속성 만 데이터베이스로 전송됩니다.

단점

  • 뷰는 모든 속성을 포함해야합니다.
  • 원본을로드 한 후 업데이트하기 위해 데이터베이스에 대한 2 x 쿼리

방법 3-업데이트 된 레코드를 연결하고 상태를 EntityState.Modified로 설정합니다.

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

장점

  • 업데이트 할 데이터베이스에 대한 쿼리 1 개

단점

  • 변경할 속성을 지정할 수 없습니다.
  • 보기에는 모든 속성이 포함되어야합니다.

질문

My question to you guys; is there a clean way that I can achieve this set of goals?

  • Can specify which properties change
  • Views don't need to contain every property (such as password!)
  • 1 x query on database to update

I understand this is quite a minor thing to point out but I may be missing a simple solution to this. If not method one will prevail ;-)


You are looking for:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

I really like the accepted answer. I believe there is yet another way to approach this as well. Let's say you have a very short list of properties that you wouldn't want to ever include in a View, so when updating the entity, those would be omitted. Let's say that those two fields are Password and SSN.

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;   

db.SaveChanges();   

This example allows you to essentially leave your business logic alone after adding a new field to your Users table and to your View.


foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();

I have added an extra update method onto my repository base class that's similar to the update method generated by Scaffolding. Instead of setting the entire object to "modified", it sets a set of individual properties. (T is a class generic parameter.)

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

And then to call, for example:

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

I like one trip to the database. Its probably better to do this with view models, though, in order to avoid repeating sets of properties. I haven't done that yet because I don't know how to avoid bringing the validation messages on my view model validators into my domain project.


public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}

Just to add to the list of options. You can also grab the object from the database, and use an auto mapping tool like Auto Mapper to update the parts of the record you want to change..


Depending on your use case, all the above solutions apply. This is how i usually do it however :

For server side code (e.g. a batch process) I usually load the entities and work with dynamic proxies. Usually in batch processes you need to load the data anyways at the time the service runs. I try to batch load the data instead of using the find method to save some time. Depending on the process I use optimistic or pessimistic concurrency control (I always use optimistic except for parallel execution scenarios where I need to lock some records with plain sql statements, this is rare though). Depending on the code and scenario the impact can be reduced to almost zero.

For client side scenarios, you have a few options

  1. Use view models. The models should have a property UpdateStatus(unmodified-inserted-updated-deleted). It is the responsibility of the client to set the correct value to this column depending on the user actions (insert-update-delete). The server can either query the db for the original values or the client should send the original values to the server along with the changed rows. The server should attach the original values and use the UpdateStatus column for each row to decide how to handle the new values. In this scenario I always use optimistic concurrency. This will only do the insert - update - delete statements and not any selects, but it might need some clever code to walk the graph and update the entities (depends on your scenario - application). A mapper can help but does not handle the CRUD logic

  2. Use a library like breeze.js that hides most of this complexity (as described in 1) and try to fit it to your use case.

Hope it helps

참고URL : https://stackoverflow.com/questions/15336248/entity-framework-5-updating-a-record

반응형