[C#] 엔티티 프레임 워크 4-AddObject와 Attach

나는 최근에 엔티티 프레임 워크 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 문만 실행됩니다.



답변

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


답변

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

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

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”는 연결이 끊어집니다.

그렇게 이해합니다.


답변

이것은 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 메소드를 사용하여 기존 대상을 삭제하도록 등록합니다.


답변

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

즉 :

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


답변