2010-02-18 3 views
8

.NET에서 Entity Framework 사용 데이터베이스에서 반환 된 항목 목록을 반복하여 업데이트하려고합니다. http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/8a337036-d288-48d4-80d4-89e5a51eddd9?ppud=4 S Hargroves가 IList의 변환을 제안하고 그 용액이다 따르면.NET EntityFramework : "공급자 연결에서 트랜잭션을 시작하는 동안 오류가 발생했습니다. 자세한 내용은 내부 예외를 참조하십시오."

var qry = (from c in DBEntities.Customer select c); 
foreach (Object item in qry) 
{ 
    item.FirstName = .... 
    ... etc, other code here 
    DBEntities.SaveChanges(); 
} 

.

시도해 보지 않으셨습니까? 작동 여부는 확실하지만 작동해도 루프 중에 항목을 업데이트 할 수없는 이유를 알고 싶습니다. 다른 사용자가 데이터베이스에 접속하지 않아도 내 지역 개발 환경에서 이러한 현상이 발생합니다.

감사합니다 ...

+0

내부 예외는 무엇을 말 했는가? 일반적으로 예외를 잡아 내고'ex.ToString()'의 결과를 게시해야합니다. 그런 다음 "던져야합니다." 다시, "ex.ToString()"예외를 처리하지 않기 때문에. –

답변

3
나는 VAR에게 목록을 만들기로 동의

. 그런 다음 foreach에서 qry의 Object 항목을 사용하는 대신 qry에서 Customer customer를 사용하십시오. 이 시나리오에서는 고객뿐만 아니라 객체로도 작업하고 있습니다. 대부분의 경우, 매번 실행될 때마다 서버에서 업데이트 명령을 실행하므로 foreach에서 SaveChanges()를 호출하지 않으려합니다. foreach 후에 이것을 수행하면 데이터베이스에 대한 호출을 한 번 수행하고 훨씬 좋은 결과를 얻을 수 있습니다.

내 제안 의사 코드는 루프 후 SavingChanges에 추천에 대한

var customers = (from c in DBEntities.Customer select c).ToList<Customer>(); 
foreach (Customer customer item in customers) 
{ 
    customer.FirstName = .... 
    ... etc, other code here 

} 
DBEntities.SaveChanges(); 
0

감사합니다 같은 것을, 나는 그 생각을하지 않았다 보인다. 그러나 1 백만 개가 넘는 레코드를 처리해야합니다.이 모든 것이 그리 많지는 않지만 각 루프 중에 수행 될 일부 처리가 있습니다. 따라서 정보를 업데이트하는 1 백만 개의 레코드를 반복하고 변경 사항을 게시하는 데 시간이 오래 걸릴 것이라고 생각합니다.

또한 EntityFramework가 아마도 최선의 방법이 아니라는 것을 알고 있지만 Entity Framework의 기능과 한계를 배우는 데 관심이 있습니다.

또한 var 목록을 참고하면 실제로 Customer 유형 인 CustomerQuery가 반환됩니다. 따라서 foreach 루프는 목록으로 변환하지 않고도 Customer 변수 데이터 형식을 사용하여 위와 같이 작성할 수 있습니다.

또 내가 궁금한 점은 루프 중에 동일한 컨텍스트 개체 (DBEntities)에 변경 사항을 게시 할 수 없다는 것입니다.

+2

질문에 '답변'으로 더 많은 정보를 게시하지 말고 원래 질문을 편집하십시오. – StarCub

11

쿼리에서 SaveChanges를 사용하여 데이터베이스를 업데이트하면 쿼리가 무효화됩니다. 수행 한 업데이트로 인해 결과 집합이 변경되었을 수 있습니다.

ToList을 사용하면 쿼리 실행을 트리거하고 데이터베이스의 모든 결과를 메모리로 가져 오게됩니다. 메모리 내 목록은 이제 구체적이고 쿼리가 더 이상 필요하지 않습니다.

개체 쿼리는 IEnumerable을 사용하므로 foreach로 목록을 수정하는 작업을 수행하지 마십시오.

은 또한이 코드는 동일한 기본 이유로 실패 할 것이라고 생각 :

List<int> numbers = new List<int>() { 1,2,3,4,5,6}; 
foreach(var num in numbers) 
    numbers.Remove(num); //Invalidates the Enumerator being used in the foreach 
+0

ToList를 호출하면 해결책이 될 수 있지만 쿼리에 50,000 개 이상의 레코드가 포함되어 있다면 어떻게 될까요? 한 번에 너무 많은 데이터를 가져와 메모리로 가져올 수 있습니다. –

+0

원본 코드는 동일한 문제가 있습니다. 내가 아는 한, EF는 ObjectQuery를 열거 할 때 결과의 '페이징'을 수행하지 않습니다. 원래 쿼리를 일괄 처리하는 방법을 찾거나 @Ron과 같은 두 가지 컨텍스트 옵션을 사용하여 제안합니다. – Tilendor

3

이 좋아 저도 같은 문제에 달려있다. 지금은 약 20 만 건의 레코드가 없지만 테이블을 처리하려는 테이블은 이미지를 저장하므로 목록에 테이블을 처리 할 때 너무 오래 걸릴 수 있습니다. 데스크톱 응용 프로그램에서도 마찬가지입니다.

LinqToSql이 나온 이후 LinqToSql에서 제대로 작동하므로 Entity에서 작동하지 않는 것을 보았을 때 다소 화가났습니다. 그리고 Microsoft는 Entity에서 작동시키지 않았지만 여기서는 해결 방법이 있습니다. 2 개의 Context 객체를 작성합니다. 하나는 목록 용이고 다른 하나는 다음과 같습니다.

entityList _imgList = new entityList(); 
entityList _imgSave = new entityList(); 

// Now the 1st time I did this I got the whole record like follows. 

    var _imgList = _imgList.Images.where(i=> i.NotProcessed == false); 
    foreach(Images _img_p in imgList) 
    { 
     if(something) 
     { 
      Images _img = _imgSave.Single(i=> i.ID == _img_p.ID); 
      _img.NotProcessed == true; 
      imgSave.SaveChanges(); 
     } 
    } 
imgList.dispose(); 
imgSave.dispose(); 


// After i verified this worked I figured why do I need to whole record to loop though so I changed it to just get the ID then process my loop as follows, and it works great. 

    var _imgIds = _imgList.Images.where(i=> i.NotProcessed == false).select(i=>i.ID); 
    foreach(long _imgID in imgList) 
    { 
     Images _img = _imgSave.Single(i=> i.ID == _imgID); 
     if(something) 
     { 
      _img.NotProcessed == true; 
      imgSave.SaveChanges(); 
     } 
    } 

imgList.dispose(); 
imgSave.dispose(); 

당신은 내 블로그 포스트에서 자세한 내용을 볼 수 있습니다 (ASP.Net Help Blog)

+0

P. 루프가 작동 한 후에도 변경 사항을 저장하지만 모양이 변경 될 때마다 변경 사항을 적용해야하는 경우 – Ron

관련 문제