Если вы перейдете сюда: 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);
}
Department.cs
Код: Выделить всё
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();
}
Код: Выделить всё
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
Мобильная версия