왜 당신의 EF 핵심 코드가 지금 얄밉게 변했습니까?트리스터 ()

6875 단어 csharpdotnet

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에서 온 주석


다음과 같은 경우에 귀하는 명확하게 고객 평가를 강제해야 할 수도 있습니다
  • 데이터의 양이 매우 적기 때문에 클라이언트에서 평가를 하면 막대한 성능 손실이 발생하지 않는다.
  • 사용 중인 LINQ 연산자에 서버 측 번역이 없습니다.
  • AsEnumerable를 사용하면 결과를 스트리밍할 수 있지만 ToList를 사용하면 목록이 만들어져 버퍼링이 발생하고 추가 메모리가 필요합니다.그러나 여러 번 열거하려면 데이터베이스에 조회가 하나밖에 없기 때문에 결과를 목록에 저장하는 것이 더 도움이 될 것이다.구체적인 사용 상황에 따라 당신은 어떤 방법이 이 사례에 더욱 유용한지 평가해야 합니다.
    https://docs.microsoft.com/en-us/ef/core/querying/client-eval

    읽어주셔서 감사합니다.


    좋은 웹페이지 즐겨찾기