Правильно ли EF Core 8.0.20 обрабатывает запросы AsSplitQuery с условиями и подкачкой, которые извлекают данные из таблиC#

Место общения программистов C#
Ответить
Anonymous
 Правильно ли EF Core 8.0.20 обрабатывает запросы AsSplitQuery с условиями и подкачкой, которые извлекают данные из табли

Сообщение Anonymous »

Знаете ли вы, что EF Core правильно обрабатывает запросы, которые применяют фильтры и разбиение по страницам, а также выбирают данные из таблиц с отношениями «один ко многим» при использовании .AsSplitQuery()?
Если вы перейдете сюда: https://learn.microsoft.com/en-ca/ef/co ... it-queries, там написано:

Предупреждение
При использовании разделенных запросов с параметрами Skip/Take для версий EF до 10 обратите особое внимание на то, чтобы порядок запросов был полностью уникальным; невыполнение этого требования может привести к возврату неверных данных. Например, если результаты упорядочены только по дате, но может быть несколько результатов с одной и той же датой, тогда каждый из разделенных запросов может получить разные результаты из базы данных. Упорядочение по дате и идентификатору (или любому другому уникальному свойству или комбинации свойств) делает упорядочение полностью уникальным и позволяет избежать этой проблемы. Обратите внимание, что реляционные базы данных по умолчанию не применяют никакого порядка, даже к первичному ключу.

Я не совсем понимаю, что с этим делать. Я использую EF Core 8.0.20.
Основываясь на моих исследованиях, кажется, что он обрабатывает эти запросы правильно, но я боюсь, что что-то упускаю.
Вот код, который я пробовал:

Код: Выделить всё

IF EXISTS
(
SELECT 1
FROM sys.sysreferences r
JOIN sys.sysobjects o ON (o.id = r.constid AND o.type = 'F')
WHERE r.fkeyid = object_id('MainTableDepartments')
AND o.name = 'FK_MAINTABL_REFERENCE_MAINTABL'
)
ALTER TABLE MainTableDepartments
DROP CONSTRAINT FK_MAINTABL_REFERENCE_MAINTABL;
GO

IF EXISTS
(
SELECT 1
FROM sys.sysreferences r
JOIN sys.sysobjects o ON (o.id = r.constid AND o.type = 'F')
WHERE r.fkeyid = object_id('MainTableDepartments')
AND o.name = 'FK_MAINTABL_REFERENCE_DEPARTME'
)
ALTER TABLE MainTableDepartments
DROP CONSTRAINT FK_MAINTABL_REFERENCE_DEPARTME;
GO

IF EXISTS
(
SELECT 1
FROM sysobjects
WHERE id = object_id('Department')
AND type = 'U'
)
DROP TABLE Department;
GO

IF EXISTS (SELECT 1 FROM sysobjects WHERE id = object_id('MainTable') AND type = 'U')
DROP TABLE MainTable;
GO

IF EXISTS
(
SELECT 1
FROM sysobjects
WHERE id = object_id('MainTableDepartments')
AND type = 'U'
)
DROP TABLE MainTableDepartments;
GO

/*==============================================================*/
/* Table: Department                                            */
/*==============================================================*/

CREATE TABLE Department
(
DepartmentId int IDENTITY,
DepartmentName varchar(100) NOT NULL,
CONSTRAINT PK_DEPARTMENT PRIMARY KEY (DepartmentId)
);
GO

/*==============================================================*/
/* Table: MainTable                                             */
/*==============================================================*/

CREATE TABLE MainTable
(
Id int IDENTITY,
Code varchar(10) NOT NULL,
Name varchar(100) NOT NULL,
CONSTRAINT PK_MAINTABLE PRIMARY KEY (Id)
);
GO

/*==============================================================*/
/* Table: MainTableDepartments                                  */
/*==============================================================*/

CREATE TABLE MainTableDepartments
(
MainTableId int NOT NULL,
DepartmentId int NOT NULL,
CONSTRAINT PK_MAINTABLEDEPARTMENTS PRIMARY KEY (MainTableId, DepartmentId)
);
GO

ALTER TABLE MainTableDepartments
ADD CONSTRAINT FK_MAINTABL_REFERENCE_MAINTABL
FOREIGN KEY (MainTableId) REFERENCES MainTable (Id);
GO

ALTER TABLE MainTableDepartments
ADD CONSTRAINT FK_MAINTABL_REFERENCE_DEPARTME
FOREIGN KEY (DepartmentId) REFERENCES Department (DepartmentId);
GO

DECLARE @i int = 1;

-- insert 100 departments
WHILE @i 
{
entity.HasKey(e => e.DepartmentId).HasName("PK_DEPARTMENT");
});

modelBuilder.Entity(entity =>
{
entity.HasKey(e => e.Id).HasName("PK_MAINTABLE");

entity.HasMany(d => d.Departments).WithMany(p => p.MainTables)
.UsingEntity(
"MainTableDepartment",
r => r.HasOne().WithMany()
.HasForeignKey("DepartmentId")
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_MAINTABL_REFERENCE_DEPARTME"),
l => l.HasOne().WithMany()
.HasForeignKey("MainTableId")
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_MAINTABL_REFERENCE_MAINTABL"),
j =>
{
j.HasKey("MainTableId", "DepartmentId").HasName("PK_MAINTABLEDEPARTMENTS");
j.ToTable("MainTableDepartments");
});
});

OnModelCreatingPartial(modelBuilder);
}

partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
Классы сущностей:

Код: Выделить всё

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace TestEfCore.Entities;

[Table("Department")]
public partial class Department
{
[Key]
public int DepartmentId { get; set; }

[StringLength(100)]
[Unicode(false)]
public string DepartmentName { get; set; } = null!;

[ForeignKey("DepartmentId")]
[InverseProperty("Departments")]
public virtual ICollection MainTables { get; set; } = new List();
}

Код: Выделить всё

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace TestEfCore.Entities;

[Table("MainTable")]
public partial class MainTable
{
[Key]
public int Id { get; set; }

[StringLength(10)]
[Unicode(false)]
public string Code { get; set; } = null!;

[StringLength(100)]
[Unicode(false)]
public string Name { get; set; } = null!;

[ForeignKey("MainTableId")]
[InverseProperty("MainTables")]
public virtual ICollection Departments { get; set; } = new List();
}

Код: Выделить всё

Program.cs
:

Код: Выделить всё

using Microsoft.EntityFrameworkCore;
using TestEfCore.Context;

var db = new TestDbContext();

var list =
db.MainTables
.Include(t => t.Departments)
.Where(t => t.Id < 5)
.OrderBy(t => t.Code)
.Skip(2)
.Take(3)
.AsSplitQuery()
.ToList();

foreach (var mainTable in list)
{
Console.WriteLine($"{mainTable.Id} - {mainTable.Code} - {mainTable.Name}");
foreach (var dept in mainTable.Departments)
{
Console.WriteLine($"   {dept.DepartmentId} - {dept.DepartmentName}");
}
}
Проект C#:

Код: Выделить всё



Exe
net8.0
enable
enable





all
runtime; build; native; contentfiles; analyzers; buildtransitive






Выход:

Код: Выделить всё

3 - Code3 - Name3
21 - Department 21
22 - Department 22
23 - Department 23
24 - Department 24
25 - Department 25
26 - Department 26
27 - Department 27
28 - Department 28
29 - Department 29
30 - Department 30
4 - Code4 - Name4
31 - Department 31
32 - Department 32
33 - Department 33
34 - Department 34
35 - Department 35
36 - Department 36
37 - Department 37
38 - Department 38
39 - Department 39
40 - Department 40
Выполненные запросы:

Код: Выделить всё

EXEC sp_executesql N'SELECT [m].[Id], [m].[Code], [m].[Name]
FROM [MainTable] AS [m]
WHERE [m].[Id] < 5
ORDER BY [m].[Code], [m].[Id]
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY',N'@__p_0 int,@__p_1 int',@__p_0=2,@__p_1=3

EXEC sp_executesql N'SELECT [t0].[MainTableId], [t0].[DepartmentId], [t0].[DepartmentId0], [t0].[DepartmentName], [t].[Id]
FROM (
SELECT [m].[Id], [m].[Code]
FROM [MainTable] AS [m]
WHERE [m].[Id] < 5
ORDER BY [m].[Code]
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY
) AS [t]
INNER JOIN (
SELECT [m0].[MainTableId], [m0].[DepartmentId], [d].[DepartmentId] AS [DepartmentId0], [d].[DepartmentName]
FROM [MainTableDepartments] AS [m0]
INNER JOIN [Department] AS [d] ON [m0].[DepartmentId] = [d].[DepartmentId]
) AS [t0] ON [t].[Id] = [t0].[MainTableId]
ORDER BY [t].[Code], [t].[Id]',N'@__p_0 int,@__p_1 int',@__p_0=2,@__p_1=3
Выполненные запросы (то же, что и выше, но SQL отформатирован для удобства чтения):

Код: Выделить всё

SELECT
m.Id, m.Code, m.Name
FROM MainTable AS m
WHERE m.Id < 5
ORDER BY m.Code, m.Id OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY;

SELECT
t0.MainTableId, t0.DepartmentId, t0.DepartmentId0, t0.DepartmentName, t.Id
FROM
(SELECT
m.Id, m.Code
FROM MainTable AS m
WHERE m.Id < 5
ORDER BY m.Code OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY) AS t
INNER JOIN
(SELECT
m0.MainTableId, m0.DepartmentId, d.DepartmentId AS DepartmentId0, d.DepartmentName
FROM MainTableDepartments AS m0
INNER JOIN Department AS d ON m0.DepartmentId = d.DepartmentId) AS t0 ON t.Id = t0.MainTableId
ORDER BY
t.Code, t.Id;
Сгенерированные запросы выглядят правильно — оба запроса упорядочены по коду и идентификатору. Сортировка по идентификатору была добавлена ​​EF.
Вопрос в том, что может пойти не так, о чем мне следует знать.
Спасибо

Подробнее здесь: https://stackoverflow.com/questions/798 ... conditions
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»