Làm cách nào để thực hiện tham gia nhóm trong .NET Core 3.0 Entity Framework?


13

Với những thay đổi đối với .NET Core 3.0, tôi đang nhận được

... NavigationExpandingExpressionVisitor 'không thành công. Điều này có thể chỉ ra lỗi hoặc giới hạn trong EF Core. Xem https://go.microsoft.com/fwlink/?linkid=2101433 để biết thêm thông tin chi tiết.) ---> System.InvalidOperationException: Xử lý biểu thức LINQ 'GroupJoin, ...

Đây là một truy vấn thực sự đơn giản vì vậy phải có cách để thực hiện nó trong .NET CORE 3.0:

 var queryResults1 = await patients
            .GroupJoin(
                _context.Studies,
                p => p.Id,
                s => s.Patient.Id,
                (p, studies) => new 
                {
                    p.DateOfBirth,
                    p.Id,
                    p.Name,
                    p.Sex,
                   Studies =studies.Select(s1=>s1)
                }
            )
            .AsNoTracking().ToListAsync();

Về cơ bản, tôi đang tìm kiếm một truy vấn Linq (hoặc cú pháp phương pháp như trên) sẽ tham gia Nghiên cứu trên Bệnh nhân và đặt Nghiên cứu thành một danh sách trống hoặc null nếu không có nghiên cứu nào cho bệnh nhân cụ thể.

Có ý kiến ​​gì không? Điều này đã làm việc trong .NET Core 2.2. Ngoài ra, liên kết MSFT ở trên đề cập rằng thay đổi ngắt chính có liên quan đến đánh giá phía máy khách và tránh việc truy vấn được tạo sẽ đọc toàn bộ các bảng mà sau đó phải được nối hoặc lọc phía máy khách. Tuy nhiên với truy vấn đơn giản này, việc tham gia nên dễ dàng thực hiện phía máy chủ.

Câu trả lời:


11

Như đã thảo luận ở đây , bạn đang cố gắng truy vấn không được cơ sở dữ liệu hỗ trợ. EF Core 2 đã sử dụng đánh giá phía máy khách để làm cho mã của bạn hoạt động, nhưng EF Core 3 từ chối, vì sự tiện lợi của phía máy khách phải trả giá bằng các vấn đề về hiệu năng khó gỡ lỗi khi tăng dữ liệu.

Bạn có thể sử dụng DefaultIfEmptyđể rời khỏi tham gia các nghiên cứu của bệnh nhân và sau đó nhóm bằng tay ToLookup.

var query =
    from p in db.Patients
    join s in db.Studies on p.Id equals s.PatientId into studies
    from s in studies.DefaultIfEmpty()
    select new { Patient = p, Study = s };

var grouping = query.ToLookup(e => e.Patient); // Grouping done client side

Ví dụ trên lấy toàn bộ thực thể Bệnh nhân và Nghiên cứu, nhưng thay vào đó bạn có thể chọn các cột anh đào. Nếu dữ liệu bạn cần từ Bệnh nhân quá lớn để lặp lại cho mỗi Nghiên cứu, trong truy vấn đã tham gia, chỉ chọn ID Bệnh nhân, truy vấn phần còn lại của dữ liệu Bệnh nhân trong một truy vấn không tham gia riêng biệt.


2
Trả lời công trình! Tôi đoán vẫn còn một số việc phải làm trong trình dịch truy vấn. Một truy vấn đơn giản như thế này có thể dịch được. Không nên có vấn đề về hiệu năng cho một nhóm đơn giản gồm 2 bảng vì tập dữ liệu tăng giả sử FK / chỉ mục là chính xác. Tôi nghi ngờ nhiều người sẽ gặp vấn đề, tham gia nhóm 2 bảng là một truy vấn khá chuẩn và thường được sử dụng.
Shelbypereira

@ she72 Tôi đồng ý. Có vẻ như vấn đề bắt nguồn từ sự khác biệt trong cách LINQ và SQL sử dụng từ khóa "nhóm". EF Core nên dịch LINQ groupbysang các liên kết bên trái trong đó làm như vậy không kéo lại nhiều hàng hơn dự kiến. Tôi đã đăng một bình luận phù hợp.
Edward Brey

Tôi có một câu hỏi tiếp theo, tôi vẫn đang cố gắng để hiểu tại sao việc phân nhóm cho loại truy vấn này cần phải được thực hiện phía máy khách, có vẻ như là một hạn chế của khung LINQ mới. Đối với trường hợp trên, tôi không thấy bất kỳ rủi ro nào làm chậm việc thực hiện phía máy khách theo những cách không mong muốn. Bạn có thể làm rõ?
Shelbypereira

1
Và như một sự theo dõi tiếp theo, mối quan tâm chính là: trong truy vấn được điều chỉnh của bạn, nhóm khách hàng nào nếu tôi có 1000 nghiên cứu cho mỗi bệnh nhân, tôi sẽ tải mỗi bệnh nhân 1000 lần từ DB? Có cách nào khác để buộc công việc này được thực hiện trong DB và trả về kết quả được nhóm không?
Shelbypereira

1
@ shev72 Việc phân nhóm duy nhất cơ sở dữ liệu hiểu liên quan đến tổng hợp, ví dụ như một truy vấn của bệnh nhân với số lượng nghiên cứu trên mỗi bệnh nhân. Cơ sở dữ liệu luôn trả về một tập dữ liệu hình chữ nhật. Một nhóm phân cấp phải được soạn bởi khách hàng. Bạn có thể xem nó như là đánh giá phía khách hàng hoặc là một phần của ORM . Trong một nhóm phân cấp, dữ liệu thực thể cha mẹ được lặp lại, mặc dù không được truy vấn lại.
Edward Brey

0

Có chính xác cùng một vấn đề và một cuộc đấu tranh lớn với nó. Hóa ra .net Core 3.0 không hỗ trợ Tham gia hoặc Groupjoin theo cú pháp phương thức (chưa?). Mặc dù vậy, phần thú vị là nó hoạt động theo cú pháp Truy vấn.

Hãy thử điều này, đó là cú pháp truy vấn với một chút cú pháp phương thức. Điều này chuyển dịch độc đáo sang truy vấn SQL chính xác với một kết nối bên ngoài bên trái đẹp và nó được xử lý trên cơ sở dữ liệu. Tôi chưa có mô hình của bạn nên bạn cần tự kiểm tra cú pháp ....

var queryResults1 = 
    (from p in _context.patients
    from s in _context.Studies.Where(st => st.PatientId == p.Id).DefaultIfEmpty()
    select new
    {
        p.DateOfBirth,
        p.Id,
        p.Name,
        p.Sex,
        Studies = studies.Select(s1 => s1)
    }).ToListAsync();

Nhân tiện, Tham gia và GroupJoin với phương pháp tổng hợp DO hoạt động với Khung không lõi và EF. Và thực hiện dịch sang đúng truy vấn được đặt ở phía máy chủ
hwmaat

1
nghiên cứu trong nghiên cứu là gì. Chọn (s1 => s1)
Ankur Arora

Các mô hình không được bao gồm trong câu hỏi vì vậy tôi không biết mô hình nghiên cứu. Dự đoán tốt nhất của tôi là đây là một bộ sưu tập ảo trong mô hình.
hwmaat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.