엔티티 프레임 워크 코어를 사용하여 레코드를 업데이트하는 방법은 무엇입니까?


88

엔티티 프레임 작업 코어에서 데이터베이스 테이블 데이터를 업데이트하는 가장 좋은 방법은 무엇입니까?

  1. 테이블 행을 검색하고 변경을 수행하고 저장하십시오.
  2. DB 컨텍스트에서 키워드 업데이트 를 사용 하고 존재하지 않는 항목에 대한 예외 처리

EF6에서 사용할 수있는 향상된 기능은 무엇입니까?

답변:


104

Entity Framework Core로 엔터티를 업데이트하기위한 논리적 프로세스는 다음과 같습니다.

  1. DbContext클래스에 대한 인스턴스 만들기
  2. 키로 항목 검색
  3. 엔터티 속성 변경
  4. 변경 사항을 저장하다

Update()방법 DbContext:

SaveChanges()호출 될 때 데이터베이스에서 업데이트되도록 수정 됨 상태에서 지정된 엔티티 추적을 시작합니다 .

업데이트 방법은 데이터베이스에 변경 사항을 저장하지 않습니다. 대신 DbContext 인스턴스의 항목에 대한 상태를 설정합니다.

따라서 Update()데이터베이스에 변경 사항을 저장하기 전에 메서드를 호출 할 수 있습니다 .

귀하의 질문에 답하기 위해 몇 가지 객체 정의를 가정하겠습니다.

  1. 데이터베이스 이름은 Store입니다.

  2. 테이블 이름은 제품입니다.

제품 클래스 정의 :

DbContext 클래스 정의 :

엔티티 업데이트 로직 :


1
감사합니다 . 2. DB 컨텍스트에서 키워드 업데이트를 사용하고 존재하지 않는 항목에 대한 예외를 처리하는 방법에 대한 좋은 예입니다. 모범 사례로 사용할 것을 선택하는 데 더 관심이 있습니다.
Charith 2017-10-15

왜 nullable int?을 사용 ProductID했나요? 선택적 기본 키가됩니까?
Artificial Stupidity

8
실제로 context.Products.Update 줄은 컨텍스트에서 검색하면 엔티티가 추적되므로 중복됩니다. 여기에 서로 다른 접근 방식의 훌륭한 개요는 다음과 같습니다 learnentityframeworkcore.com/dbcontext/modifying-data
요한 메이스

67

Microsoft 문서 에 따르면 :

읽기 우선 접근 방식에는 추가 데이터베이스 읽기가 필요하며 동시성 충돌을 처리하기 위해 더 복잡한 코드가 발생할 수 있습니다.

그러나 DbContext에서 Update 메서드를 사용하면 모든 필드가 수정 된 것으로 표시되고 모든 필드 가 쿼리에 포함 된다는 것을 알아야 합니다. 필드의 하위 집합을 업데이트하려면 Attach 메서드를 사용한 다음 원하는 필드를 수동 으로 수정 된 것으로 표시 해야합니다.


31
이 API의 단지 작은 판, 지금은 더 강하게가 입력 된 버전 : context.Entry(person).Property(p => p.Name).IsModified = true;
전문가 Stron

2
또한 간단하게 할 수있는context.Entry(person).State = EntityState.Modified;
르낭 코엘류에게

1
이 context.Entry (person) .State = EntityState.Modified; 평균? 여러 필드를 수정하는 경우이 행을 변경해야합니까?
user989988

2
좋은 포인트 ehsan jan! ; D 또한 엔터티가 사용자에 의해 업데이트되고 필드가 수정되었는지 모르거나 신경 쓰지 않는 _context.Attach(person).State = EntityState.Modified; 경우이 엔터티가 SaveChanges 메서드에서 업데이트 될 것임을 나타내는 데 사용할 수 있습니다 .
S.Serpooshan 2019

대단한 캐치. 따라서 컨텍스트가 "고정"되어야하므로 컨텍스트의 엔티티에 대해 알고 있습니다. 방금 테스트했는데 존재하지 않는 항목을 편집하려고하면 예외가 발생합니다! :) 하나 이상의 오류가 발생했습니다. (업데이트하거나 저장소에 존재하지 않는 개체를 삭제하는 시도했습니다.)
granadaCoder

31
public async Task<bool> Update(MyObject item)
{
    Context.Entry(await Context.MyDbSet.FirstOrDefaultAsync(x => x.Id == item.Id)).CurrentValues.SetValues(item);
    return (await Context.SaveChangesAsync()) > 0;
}

이 방법은 정말 잘 작동한다고 생각하지만 더 많은 컨텍스트를 사용할 수 있었기 때문에 게시물이 아래에 있다고 생각합니다. 하지만 좋아!
Mr. Kraus

1
나도 좋아해! @씨. Krause는 그것이 불과 며칠이라는 이유로 게시물이 (지금까지) 낮지 않았습니까?
Wellspring

1
"PRIMARY KEY 제약 조건 'PK_Offer'위반입니다. 'dbo.Offer'개체에 중복 키를 삽입 할 수 없습니다."이 메시지가 표시됩니다.
Magnus Karlsson 19

8

Microsoft Docs 는 두 가지 접근 방식을 제공합니다.

권장 HttpPost 편집 코드 : 읽기 및 업데이트

이것은 이전 버전의 Entity Framework에서 사용했던 것과 동일한 이전 방식입니다. 이것이 Microsoft가 우리에게 권장하는 것입니다.

장점

  • 초과 게시 방지
  • EF의 자동 변경 내용 추적은 Modified양식 입력에 의해 변경되는 필드에 플래그를 설정합니다 .

대체 HttpPost 편집 코드 : 생성 및 첨부

대안은 모델 바인더로 만든 엔터티를 EF 컨텍스트에 연결하고 수정 된 것으로 표시하는 것입니다.

다른 답변에서 언급했듯이 읽기 우선 접근 방식에는 추가 데이터베이스 읽기가 필요하며 동시성 충돌을 처리하기 위해 더 복잡한 코드가 발생할 수 있습니다.


8

아주 간단합니다

using (var dbContext = new DbContextBuilder().BuildDbContext())
{
    dbContext.Update(entity);
    await dbContext.SaveChangesAsync();
}

2

모든 답을 살펴본 후 두 가지 간단한 옵션을 추가 할 것이라고 생각했습니다.

  1. 추적이 활성화 된 상태에서 FirstOrDefault ()를 사용하여 레코드에 이미 액세스하고 (추적을 비활성화하므로 .AsNoTracking () 함수를 사용하지 않고) 일부 필드를 업데이트 한 경우 간단히 context.SaveChanges ()를 호출 할 수 있습니다.

  2. 다른 경우에는 HtppPost를 사용하여 서버에 엔티티를 게시했거나 어떤 이유로 추적을 비활성화 한 다음 context.SaveChanges () 전에 context.Update (entityName)를 호출해야합니다.

첫 번째 옵션은 변경 한 필드 만 업데이트하지만 두 번째 옵션은 실제로 업데이트 된 필드 값이 없더라도 데이터베이스의 모든 필드를 업데이트합니다. :)


0

보다 일반적인 접근 방식

이 접근 방식을 단순화하기 위해 "id"인터페이스가 사용됩니다.

public interface IGuidKey
{
    Guid Id { get; set; }
}

도우미 방법

    public static void Modify<T>(this DbSet<T> set, Guid id, Action<T> func)
        where T : class, IGuidKey, new()
    {
        var target = new T
        {
            Id = id
        };
        var entry = set.Attach(target);
        func(target);
        foreach (var property in entry.Properties)
        {
            var original = property.OriginalValue;
            var current = property.CurrentValue;

            if (ReferenceEquals(original, current))
            {
                continue;
            }

            if (original == null)
            {
                property.IsModified = true;
                continue;
            }

            var propertyIsModified = !original.Equals(current);
            property.IsModified = propertyIsModified;
        }
    }

용법

dbContext.Operations.Modify(id, x => { x.Title = "aaa"; });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.