왜 당신의 EF 핵심 코드가 지금 얄밉게 변했습니까?트리스터 ()
tl;박사
과거 EF Core에서 마법을 통해 일어났던 일들이 현재는 호출
AsEnumerator()
또는 ToList()
을 통해 현저하게 발생해야 한다.https://docs.microsoft.com/en-us/ef/core/querying/client-eval
배경.
이 글은 순전히 일화일 뿐, 실제로는 나의 관점과 과거의 경험만 반영했기 때문에 나는 매우 뚜렷한 일을 놓쳤을 수도 있다. 그래서 나는 미리 사과한다.
솔리드 프레임워크에서는 서버에서 수행할 수 있는 모든 작업(예: SQL)이 성능을 향상시킵니다.
이것은 일부 물건입니다. 예를 들어 이 문자열 = = 저 문자열 또는 이 id = 저 id 또는 이 목록은 이 물건을 포함합니다.
사용자 정의 메서드나 문자열과 같은 SQL로 변환할 수 없는 작업은 클라이언트에서 수행됩니다(C#에서는 기본 수준).
이러한 클라이언트 평가는 EF Core 2와 3 사이에 처리 방식이 변경되었기 때문에 작업하려는 모든 데이터를 메모리에 로드해야 합니다.
EF 코어<3
EF Core 3 이전 버전의 클라이언트 컴퓨팅은 메모리에 동적으로 암시적으로 로드되어 아무런 차이 없이 실행됩니다.
그 자체로 문제가 많다.자신도 모르게 수백만 줄을 메모리에 불러오고 한 줄에 대해 어떤
string.Equals()
조작을 해서 기록을 얻고 있다고 상상해 보세요.이것은 고도의 가설적인 문제이다. 나는 우리가 더 이상 공공장소에서 이야기하지 않는 어두운 날에 우리는 모두 이 문제를 만났다고 확신한다.EF Core 3 이 문제를 해결하려고 합니다.
EF 코어>3
EF Core 3 이상 릴리즈에서는 이러한 컨텐트를 메모리에 명시적으로 로드하기 위해 강제 호출
.AsEnumerable()
또는 비동기식 항목을 사용합니다.메모리 호출에 줄을 현저하게 끌어다 놓지 않으면dotnet에서 실행 중 이상을 던집니다. 이것은 실제적으로 매우 유용합니다. 실행 중인 검색을 서버에서 실행할 수 있도록 SQL로 변환할 수 없기 때문에
.ToList()
등에 대한 호출을 추가해야 합니다.코드 좀 봅시다 (msdn:)
public static string StandardizeUrl(string url)
{
url = url.ToLower();
if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
return url;
}
var blogs = context.Blogs
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToList();
EF Core<3에서 이러한 작업은 완벽하게 실행되므로 수행 방법이 상당히 무식합니다.그러나 EF Core 3 및 이상 버전의 새로운 변경에 따라 실행 시 이상이 발생할 수 있습니다.
.ToList()
방법은 SQL로 전환할 수 없기 때문입니다.현재 운행할 때 가장 나쁜 점은 만약에 당신이 설계한 해결 방안이 매우 나쁘고 튼튼한 원칙을 놓칠 수도 있고 심지어는 거대한 데이터 집적층만 있을 수도 있다는 것이다. 당신은 상하문에서 모든 가능한 경로/LINQ 조회를 재검토해야 하지만, 만약에 아주 좋은 집적 테스트나 자동 테스트가 있다면, 이것은 약간의 고통을 줄일 수 있을 것이다.
위 내용이 EF Core>3에서 작용하도록 하려면 이렇게 써도 된다
var blogs = context.Blogs
.AsEnumerable()
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToList();
StandardizeUrl
호출은 AsEnumerable
의 모든 내용을 불러오고 클라이언트에서 Where 자구를 실행합니다.이전하기 전에 제가 무엇을 할 수 있습니까?
db 컨텍스트에서 다음 코드를
context.Blogs
메서드에 추가할 수 있습니다.protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;")
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}
이는 EF Core 2에서 클라이언트 쿼리 값을 구하는 기능을 수행하지 못하도록 하므로 작성된 코드가 성능에 미치는 영향을 보다 명확하게 파악할 수 있습니다.결론
이 변화는 좀 낙담스럽지만 개발자로서 더 많은 통찰력을 갖게 해 주었고, 데이터 추출을 위한 LINQ를 더욱 잘 알게 해 주었다고 생각한다.
클라이언트로 이동하기 전에 가능한 한 서버 측의 조회와 데이터 블록에 의존한다(ID를 사용하거나 서버 친선 코드를 사용하여 비교한다)
msdn에서 온 주석
다음과 같은 경우에 귀하는 명확하게 고객 평가를 강제해야 할 수도 있습니다
https://docs.microsoft.com/en-us/ef/core/querying/client-eval
읽어주셔서 감사합니다.
Reference
이 문제에 관하여(왜 당신의 EF 핵심 코드가 지금 얄밉게 변했습니까?트리스터 ()), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/granthair5/why-your-ef-core-code-is-now-breaking-aka-the-pesky-tolist-4766텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)