Если вы перейдете сюда: 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}");
}
}
Код: Выделить всё
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
Код: Выделить всё
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;
Вопрос в том, что может пойти не так, о чем мне следует знать.
Спасибо
Подробнее здесь: https://stackoverflow.com/questions/798 ... conditions
Мобильная версия