Wenn Sie hierher gehen: https://learn.microsoft.com/en-ca/ef/co ... it-queries, heißt es:
Warnung
Wenn Sie geteilte Abfragen mit Skip/Take in EF-Versionen vor 10 verwenden, achten Sie besonders darauf, dass die Reihenfolge Ihrer Abfragen vollständig eindeutig ist. Andernfalls könnten falsche Daten zurückgegeben werden. Wenn die Ergebnisse beispielsweise nur nach Datum sortiert sind, es aber mehrere Ergebnisse mit demselben Datum geben kann, könnte jede der geteilten Abfragen unterschiedliche Ergebnisse aus der Datenbank erhalten. Durch die Sortierung sowohl nach Datum als auch nach ID (oder einer anderen eindeutigen Eigenschaft oder Kombination von Eigenschaften) wird die Bestellung vollständig eindeutig und vermeidet dieses Problem. Beachten Sie, dass relationale Datenbanken standardmäßig keine Reihenfolge anwenden, auch nicht für den Primärschlüssel.
Ich bin mir nicht ganz sicher, was ich davon halten soll. Ich verwende EF Core 8.0.20.
Nach meinen Recherchen scheint es diese Abfragen korrekt zu verarbeiten, aber ich mache mir Sorgen, dass ich etwas übersehe.
Hier ist ein Code, den ich ausprobiert habe:
Code: Select all
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);
}
Code: Select all
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();
}
Code: Select all
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();
}
Code: Select all
Program.csCode: Select all
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}");
}
}
Code: Select all
Exe
net8.0
enable
enable
all
runtime; build; native; contentfiles; analyzers; buildtransitive
Code: Select all
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
Code: Select all
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
Code: Select all
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;
Die Frage ist, was dabei schief gehen kann, worüber ich mir im Klaren sein sollte.
Vielen Dank
Mobile version