엔티티 프레임 워크 4-AddObject와 Attach


132

나는 최근에 엔티티 프레임 워크 4와 함께 일하고있다, 약간 사용하는 경우에 관한 혼란 스러워요 ObjectSet.AttachObjectSet.AddObject을 .

내 이해에서 :

  • 엔티티가 시스템에 이미 존재하는 경우 "첨부"를 사용하십시오.
  • 새로운 엔터티를 만들 때 "AddObject"사용

따라서 새로운 Person을 만드는 경우이 작업을 수행합니다.

var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();

기존 Person을 수정하는 경우 다음을 수행하십시오.

var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();

명심하십시오. 이것은 매우 간단한 예입니다. 실제로는 순수 POCO (코드 생성 없음), 리포지토리 패턴 (ctx.Persons를 처리하지 않음) 및 작업 단위 (ctx.SaveChanges를 처리하지 않음)를 사용하고 있습니다. 그러나 "표지 아래"에서 위의 구현에서 발생합니다.

이제 내 질문 -아직 Attach 를 사용해야하는 시나리오를 찾지 못했습니다 .

내가 여기서 무엇을 놓치고 있습니까? 언제 첨부를 사용해야합니까?

편집하다

명확히하기 위해 AddObject를 통해 Attach를 사용하는 경우 (또는 그 반대)의 를 찾고 있습니다.

편집 2

아래 답변은 정확하지만 (허용됨) Attach가 유용한 다른 예를 추가한다고 생각했습니다.

의 기존 Person 수정 예제에서는 실제로 두 개의 쿼리가 실행되고 있습니다.

하나는 Person (.SingleOrDefault)을 검색하고 다른 하나는 UPDATE (.SaveChanges)를 수행합니다.

(어떤 이유로 든) 시스템에 "Joe Bloggs"가 존재한다는 것을 이미 알고 있다면 왜 먼저 추가 쿼리를 수행해야합니까? 나는 이것을 할 수있다 :

var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();

이로 인해 UPDATE 문만 실행됩니다.


모델은 EF로 직접 되돌려 놓는 요즘 MVC에서도 사용됩니다. 꽤 잘 작동하고 많은 코드 줄을 저장합니다.
Piotr Kula

답변:


162

ObjectContext.AddObject ObjectSet.AddObject : AddObject의 방법은 않습니다 새로 생성 된 개체를 추가하는 것입니다 하지 데이터베이스에 존재합니다. 엔티티는 자동으로 생성 된 임시 EntityKey를 가져 오고 해당 EntityState는
Added . SaveChanges가 호출되면이 엔티티를 데이터베이스에 삽입해야한다는 것이 EF에 명확합니다.

ObjectContext.Attach ObjectSet.Attach :
반면, Attach 는데이터베이스에이미 존재 하는 엔티티에 사용됩니다. Attach는 EntityState를 Added로 설정하지 않고 변경되지 않은 EntityState를 생성하므로 컨텍스트에 연결된 이후로 변경되지 않았습니다. 첨부중인 오브젝트가 데이터베이스에 존재한다고 가정합니다. 연결된 개체를 수정 한 후 SaveChanges를 호출하면 EntityKey 값이 db 테이블에서 일치하는 ID를 찾아 해당 행을 업데이트 (또는 삭제)하는 데 사용됩니다.

또한 Attach 메소드를 사용하여 ObjectContext에 이미 존재하지만 가지고있는 엔티티 간의 관계를 정의 할 수 있습니다.자동으로 연결 되지 않습니다 . 기본적으로, 첨부의 주요 목적은 이미 ObjectContext는에 부착되어 있습니다 연결 실체이다 없습니다 당신이 누구의 EntityState 추가 엔티티를 첨부 첨부 사용할 수 있도록 새. 이 경우 Add () 를 사용해야합니다.

예를 들어, Person 엔티티에 Address 의 콜렉션 인 Addresses 라는 탐색 특성이 있다고 가정하십시오.실재. 문맥에서 두 객체를 읽었지만 서로 관련이 없으며 그렇게 만들고 싶다고 가정 해 봅시다.

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.PersonReference.Attach(existingPerson)
ctx.SaveChanges();

답변 주셔서 감사합니다, 나는 두 (일명 첫 두 단락)의 정의를 이해합니다. 그러나 첨부를 사용해야하는 시나리오를 이해하지 못합니다. 마지막 단락이 실제로 이해가되지 않습니다 (기본적으로 처음 두 단락의 조합처럼 읽음). 위 시나리오에서 "첨부"를 사용할 위치의 예를 들어 줄 수 있습니까? 그것은 정의를 찾는 것이 아니라 예를 찾는 것입니다. 그래도 시간을 주셔서 감사합니다. :)
RPM1984

1
문제가 없습니다. 마지막 단락을 명확히하기 위해 코드 스 니펫을 추가했습니다. 관련없는 두 개의 객체가 있고 Attach를 사용하여 서로 관련시킬 수 있습니다. 다른 예는 Attach () 메소드를 사용하여 "분리 된 엔티티"를 컨텍스트에 다시 첨부하는 것입니다 (분리 된 엔티티를 컨텍스트에 다시 첨부하려는 여러 가지 이유가 있습니다)
Morteza Manavi

1
그래, 지금 당장 방금 EF4 (Julie Lerman)의 TechEd 비디오를 보았습니다. 쿼리에서 검색하지 않은 엔터티가있을 수 있지만 (즉, 연결되어 있지 않음) 해당 엔터티가 있다는 것을 알고 있으므로 첨부를 사용하여 해당 엔터티에 대한 업데이트를 수행합니다. "연결이 끊어진"엔터티가있는 시나리오를 여전히 고민하기는하지만 말이됩니다. 당신의 도움을 주셔서 감사합니다.
RPM1984

1
큰. 이 게시물을 읽을 수있는 다른 동료 개발자를 위해 비디오 링크를 공유해달라고 부탁 할 수 있습니까?
Morteza Manavi

3
RPM1984가 공유 한 위의 링크가 끊어졌으며 이제 channel9.msdn.com/Events/TechEd/NorthAmerica/2010/DEV205 로 리디렉션됩니다 . 즐기십시오
스택 됨

31

이것은 늦은 답변이지만 다른 사람들이 이것을 찾는 데 도움이 될 수 있습니다.

기본적으로 "연결되지 않은"엔티티는 "사용"범위 밖의 엔티티를 조작 할 때 발생할 수 있습니다.

Employee e = null;

using (var ctx = new MyModelContainer())
{
     e = ctx.Employees.SingleOrDefault(emp => emp .....);
}

using (var ctx2 = new MyModelContainer())
{
     e; // This entity instance is disconnected from ctx2
}

다른 "using"범위를 입력하면 "e"변수는 이전 "using"범위에 속하기 때문에 연결이 끊어지며 이전 "using"범위는 없어지고 "e"는 연결이 끊어집니다.

그렇게 이해합니다.


3
Tchi의 예제는 훌륭하고 간단한 예제입니다. 예, Employee 변수는 외부에서 선언해야합니다. 범위 밖의 e.Address.Street를 시도하고 null 참조 예외 팝업을 참조하십시오. 접속하면 애플리케이션이 두 번째 범위의 직원에 대한 DB로 돌아갈 필요가 없습니다.
Steve

9

이것은 Programming Entity Framework : DbContext의 인용문입니다.

컨텍스트에 의해 추적되지 않는 엔티티에서 제거를 호출하면 InvalidOperationException이 발생합니다. 제거하려는 엔터티가 삭제 표시해야하는 기존 엔터티인지 아니면 무시해야하는 새 엔터티인지 확실하지 않기 때문에 Entity Framework에서이 예외가 발생합니다. 이러한 이유로 연결 끊기 엔터티를 삭제됨으로 표시하기 위해 제거 만 사용할 수는 없습니다. 먼저 첨부해야합니다 .

private static void TestDeleteDestination()
{
    Destination canyon;
    using (var context = new BreakAwayContext())
    {
        canyon = (from d in context.Destinations
        where d.Name == "Grand Canyon"
        select d).Single();
    }
    DeleteDestination(canyon);
}
private static void DeleteDestination(Destination destination)
{
    using (var context = new BreakAwayContext())
    {
        context.Destinations.Attach(destination);
        context.Destinations.Remove(destination);
        context.SaveChanges();
    }
}

TestDeleteDestination 메소드는 클라이언트 애플리케이션이 서버에서 기존 대상을 페치 한 후 서버의 DeleteDestination 메소드로 전달하는 것을 시뮬레이션합니다. DeleteDestination 메서드는 Attach 메서드를 사용하여 기존 대상임을 컨텍스트에 알립니다. 그런 다음 Remove 메소드를 사용하여 기존 대상을 삭제하도록 등록합니다.


-8

첨부하는 대신 기본 키만 참조하는 것은 어떻습니까?

즉 :

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.AddressId = myAddress.Id // not -> existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.Person.Id = existingPerson.Id // not -> myAddress.PersonReference.Attach(existingPerson);
ctx.SaveChanges();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.