알아채다:
1. 이 문서에 언급된 "엔티티"는 모두 LINQ TO SQL(예: .dbml)에 의해 생성됩니다.
2. LINQ TO SQL이 테이블 연결, EntitySet 및 EntityRef를 구현하는 방법을 이해해야 합니다.
어쩌면 제목을 보고 질문이 상대적으로 추상적이라고 생각하실 수도 있으니, 문제를 자세히 설명하기 위해 예를 들어보겠습니다.
LINQ TO SQL 기반 N 계층 아키텍처에서 엔터티를 업데이트해야 하는 경우 프로세스는 다음과 같아야 합니다.
프로세스
BLL.GetModel(p=>p.id==1) --> 해당 속성(필드) 값 수정 --> BLL.Update(엔티티 엔터티) --> DAL.Update(엔티티 엔터티) --> 업데이트 성공
이때 이 엔터티를 비즈니스 계층(BLL)에서 데이터 액세스 계층(DAL)으로 전달해야 합니다. GetModel 메서드가 엔터티를 반환하면 DataContext가 즉시 해제되고 DAL이 다시 인스턴스화됩니다. 업데이트(엔터티 엔터티) 메서드가 실행됩니다. 업데이트 작업을 수행하기 위해 DataContext를 생성합니다. 전달된 엔터티가 첫 번째 DataContext에서 다른 DataContext로 전달되는 것을 볼 수 있습니다. LINQ TO SQL에서 다른 DataContext에 걸쳐 작업이 필요합니다. 먼저 수행됩니다. 즉, context.Entity.Attach(entity,true); 마지막으로 context.SubmitChanges();
코드를 살펴보겠습니다.
암호
클래스 BLL
{
개인 읽기 전용 DAL dal = new DAL();
공개 LinqToSqlProvider.User GetModel(Expression<Func<LinqToSqlProvider.User, bool>> 식)
{
dal.GetModel(표현식);
}
공개 무효 업데이트(LinqToSqlProvider.User 엔터티)
{
dal.Update(엔티티);
}
}
DAL 클래스
{
공개 LinqToSqlProvider.User GetModel(Expression<Func<LinqToSqlProvider.User, bool>> 식)
{
LinqToSqlProvider.User 항목 = 새 CriTextBroadcast.LinqToSqlProvider.User();
(CriTextBroadcastDBDataContext 컨텍스트 = DataContext) 사용
{
항목 = context.User.SingleOrDefault(표현식);
}
반품 항목;
}
공개 무효 업데이트(LinqToSqlProvider.User 엔터티)
{
(CriTextBroadcastDBDataContext 컨텍스트 = DataContext) 사용
{
context.User.Attach(entry, true);
context.SubmitChanges();
}
}
}
실제로 위 코드를 사용하여 작업할 때 다음 예외가 발생합니다.
엔터티 연결 또는 추가를 시도했습니다. 이 엔터티는 새 엔터티가 아니며 다른 DataContext에서 로드될 수 있습니다...
수많은 정보를 확인해봐도 소용이 없었는데, 마침내 외국 게시물에서도 비슷한 질문을 보게 되었습니다. 이 엔터티에 해당하는 테이블에는 사용자 -> 메시지, 사용자 -> 이미지 등과 같은 여러 관련 테이블이 있는 것으로 나타났습니다.
EntitySet<Message> 메시지와 같은 속성은 엔터티를 얻을 때 이러한 연관된 내용을 함께 읽지 않으므로 연결(Attach)할 때 이러한 속성에서 ObjectDisposedException이 발생합니다. 이 엔터티를 쿼리하는 데 사용된 항목이 해제되었습니다.
해결책:
암호
/// <요약>
/// 보조 LinqToSql 엔터티는 원래 DataContext와 분리됩니다.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
공개 정적 무효 Detatch<TEntity>(TEntity 엔터티)
{
유형 t = 엔터티.GetType();
System.Reflection.PropertyInfo[] 속성 = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach(속성의 var 속성)
{
문자열 이름 = 속성.이름;
if (property.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>))
{
property.SetValue(entity, null, null);
}
}
System.Reflection.FieldInfo[] fields = t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
foreach(필드의 var 필드)
{
문자열 이름 = field.Name;
if (field.FieldType.IsGenericType &&
field.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<>))
{
field.SetValue(엔티티, null);
}
}
System.Reflection.EventInfo eventPropertyChanged = t.GetEvent("PropertyChanged");
System.Reflection.EventInfo eventPropertyChanging = t.GetEvent("PropertyChanging");
if(eventPropertyChanged != null)
{
eventPropertyChanged.RemoveEventHandler(entity, null);
}
if(eventPropertyChanging != null)
{
eventPropertyChanging.RemoveEventHandler(entity, null);
}
}
엔터티를 얻은 후에는 Detach(entity) 메서드를 사용하여 엔터티를 원래 DataContext에서 분리한 다음 새 DataContext에 연결해야 합니다.