개체가 Entity Framework의 데이터 컨텍스트에 이미 연결되어 있는지 확인할 수 있습니까?


86

다음을 통해 주어진 컨텍스트에 이미 연결된 개체를 연결하려고 할 때 다음 오류가 발생합니다 context.AttachTo(...).

동일한 키를 가진 개체가 ObjectStateManager에 이미 있습니다. ObjectStateManager는 동일한 키를 가진 여러 개체를 추적 할 수 없습니다.

다음을 따라 무언가를 달성하는 방법이 있습니까?

context.IsAttachedTo(...)

건배!

편집하다:

Jason이 설명한 확장 방법은 비슷하지만 내 상황에서는 작동하지 않습니다.

다른 질문에 대한 답변에 설명 된 방법을 사용하여 몇 가지 작업을 수행하려고합니다.

행을 먼저 검색하지 * 않고 * Linq to Entities를 사용하여 테이블에서 하나 이상의 행을 삭제하려면 어떻게해야합니까?

내 코드는 다음과 같습니다.

var user = new User() { Id = 1 };
context.AttachTo("Users", user);
comment.User = user;
context.SaveChanges();

동일한 방법을 사용하고 더미 User개체 를 첨부하려고하는 사용자를 위해 다른 작업을 수행하는 경우를 제외하고는 정상적으로 작동 합니다. 이전에 해당 더미 사용자 개체를 연결했기 때문에 실패합니다. 이것을 어떻게 확인할 수 있습니까?

답변:


57

다음은 매우 훌륭하게 작동하는 결과입니다.

public static void AttachToOrGet<T>(this ObjectContext context, string entitySetName, ref T entity)
    where T : IEntityWithKey
{
    ObjectStateEntry entry;
    // Track whether we need to perform an attach
    bool attach = false;
    if (
        context.ObjectStateManager.TryGetObjectStateEntry
            (
                context.CreateEntityKey(entitySetName, entity),
                out entry
            )
        )
    {
        // Re-attach if necessary
        attach = entry.State == EntityState.Detached;
        // Get the discovered entity to the ref
        entity = (T)entry.Entity;
    }
    else
    {
        // Attach for the first time
        attach = true;
    }
    if (attach)
        context.AttachTo(entitySetName, entity);
}

다음과 같이 호출 할 수 있습니다.

User user = new User() { Id = 1 };
II.AttachToOrGet<Users>("Users", ref user);

context.AttachTo(...)매번 위에서 인용 한 ID 트릭을 사용할 수 있다는 점을 제외하면 매우 훌륭하게 작동합니다 . 이전에 부착 된 객체 또는 부착 된 자신의 객체로 끝납니다. CreateEntityKey컨텍스트를 호출 하면 멋지고 일반적이며 더 이상 코딩하지 않고도 복합 키로도 작동합니다 (EF가 이미이를 수행 할 수 있기 때문입니다!).


나는 비슷한 문제를 겪고 있었고 이것은 내 문제를 해결했습니다. +1
RPM1984 2010

4
문자열 매개 변수가 엔티티가 속한 컬렉션의 선택기 함수로 대체되면 더 좋을 것입니다.
Jasper

1
(T)entry.Entity때때로 null을 반환하는 이유 는 무엇입니까?
Tr1stan 2010

1
내 entitySetName을 무엇으로 설정해야하는지 알 수 없습니다. 계속 예외가 발생합니다. 내가 원하는 것은 사용자를 삭제하는 것뿐이므로 너무 많은 숨겨진 말도 안되는 내 응용 프로그램을 날려 버리고 싶지 않습니다.
Julie

1
만약 T이미 IEntityWithKey, 당신은 entity.EntityKey그것을 재구성하는 것보다 속성을 사용 하거나 추측 / 제공 할 필요가 EntitySetName있습니까?
drzaus

54

더 간단한 방법은 다음과 같습니다.

 bool isDetached = context.Entry(user).State == EntityState.Detached;
 if (isDetached)
     context.Users.Attach(user);

1
이것은 나를 위해 일한, 그냥 단지 ... "분리"대신 "EntityState.Detached"를 사용했다
마르셀 Myara에게

22
흠 귀하의 솔루션을 시도했지만 저에게는 isDetached가 사실이지만 컨텍스트에 항목을 첨부하려고 할 때 여전히 동일한 오류가 발생합니다
Prokurors

훌륭한 appraoch. 내 Generic Repository에서도 작동했습니다.
ATHER 2015 년

5
그 @Prokurors 나는 최근 MOSH의 검사는 항상 오류를 방지하는 것만으로는 충분하지 않습니다 이유를 알게된다 .Include()'에드 탐색 특성은 전화 할 때 첨부 할 시도하는 .Attach또는이 설정 EntityStateEntityState.Unchanged- 엔티티의이 참조하는 경우 그들은 충돌 것 같은 개체. 기본 엔터티 만 연결하는 방법을 알지 못했기 때문에 설계된 것처럼 각 "비즈니스 트랜잭션"에 대해 별도의 컨텍스트를 사용하기 위해 프로젝트를 약간 다시 디자인해야했습니다. 나는 향후 프로젝트를 위해 이것을 주목할 것입니다.
Aske B.

18

이 확장 방법을 시도해보십시오 (테스트되지 않았으며 즉시 사용 가능).

public static bool IsAttachedTo(this ObjectContext context, object entity) {
    if(entity == null) {
        throw new ArgumentNullException("entity");
    }
    ObjectStateEntry entry;
    if(context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry)) {
        return (entry.State != EntityState.Detached);
    }
    return false;
}

편집에서 설명하는 상황을 감안할 때 EntityKey객체 대신를 허용하는 다음 오버로드를 사용해야 할 수 있습니다 .

public static bool IsAttachedTo(this ObjectContext, EntityKey key) {
    if(key == null) {
        throw new ArgumentNullException("key");
    }
    ObjectStateEntry entry;
    if(context.ObjectStateManager.TryGetObjectStateEntry(key, out entry)) {
        return (entry.State != EntityState.Detached);
    }
    return false;
}

EntityKey상황에 맞게 구축하려면 다음을 지침으로 사용하십시오.

EntityKey key = new EntityKey("MyEntities.User", "Id", 1);

속성을 사용하여의 EntityKey기존 인스턴스에서을 가져올 수 있습니다 (interface에서 ).UserUser.EntityKeyIEntityWithKey


이것은 매우 좋지만 내 상황에서는 작동하지 않습니다. 자세한 내용으로 질문을 업데이트하겠습니다. 추신 당신은 부울이 아닌 부울을 원하고 정적이지만 꽤 멋진 확장 방법 외에는 다릅니다!
joshcomley 2009

@joshcomley : 나는 당신이 오버로드를 사용하여 해결할 수 있다고 생각 TryGetObjectStateEntry하는이 받아들이는 EntityKey대신의 object. 그에 따라 편집했습니다. 이것이 도움이되지 않는 경우 알려 주시면 다시 도면으로 돌아가겠습니다.
jason

아 방금 이것을 봤습니다-방금 게시 한 답변에 설명 된 솔루션을 작업 중이었습니다. 당신의 도움과 조언을 위해 +1 !!
joshcomley 2009

내가 오류를 얻고있다 왜 모든 아이디어, 세부 사항은 여기 stackoverflow.com/questions/6653050/...
Joper

6

확인하려는 개체의 엔터티 키 사용 :

var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey");
if (entry.State == EntityState.Detached)
{
  // Do Something
}

친절,


0

이것은 OPs 질문에 직접 대답하지는 않지만 이것이 내가 어떻게 해결했는지입니다.

DbContext대신을 사용 하는 사람들을위한 것입니다 ObjectContext.

    public TEntity Retrieve(object primaryKey)
    {
        return DbSet.Find(primaryKey);
    }

DbSet.Find 메서드 :

주어진 기본 키 값이있는 항목을 찾습니다. 주어진 기본 키 값을 가진 엔터티가 컨텍스트에 있으면 저장소에 요청하지 않고 즉시 반환됩니다. 그렇지 않으면 주어진 기본 키 값을 가진 엔티티에 대한 요청이 저장소에 작성되고이 엔티티가 발견되면 컨텍스트에 첨부되고 리턴됩니다. 컨텍스트 또는 저장소에 엔티티가 없으면 null이 반환됩니다.

기본적으로 주어진의 첨부 된 객체를 반환하므로 반환 된 객체에 primaryKey변경 사항을 적용하여 올바른 인스턴스를 유지하기 만하면됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.