Category
nmのBlog
関係を仮定しましょう:
CREATE TABLE Categories(
Id INT IDENTITY(1,1) NOT NULL,
Title NVARCHAR(MAX) NOT NULL,
Created datetime NOT NULL,
CONSTRAINT PK_Categories PRIMARY KEY(Id)
)
CREATE TABLE Posts(
Id INT IDENTITY(1,1) NOT NULL,
Subject NVARCHAR(MAX) NOT NULL,
Body NVARCHAR(MAX) NULL,
CONSTRAINT PK_Posts PRIMARY KEY (Id)
)
CREATE TABLE PostCategory(
CategoryId INT NOT NULL,
PostId INT NOT NULL,
CONSTRAINT PK_PostCategory PRIMARY KEY (CategoryId, PostId),
FOREIGN KEY ([CategoryId]) REFERENCES [Categories]([Id]),
FOREIGN KEY ([PostId]) REFERENCES [Posts]([Id])
)
データベースをスキャフォールディングした後(https://docs.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db#reverse-engineer-your-modelを参照)、最初のクエリを開始しました。
var postsWithLatestCategoryTimestamp = (
from post in db.Posts
let latestCategoryTimestamp =
(
from relation in post.PostCategory
orderby relation.Category.Created descending
select relation.Category.Created
)
.FirstOrDefault()
select new
{
post.Id, post.Subject, latestCategoryTimestamp
}
).ToList();
私は得た
System.Data.SqlClient.SqlException: '文字列から日付や時刻を変換するときに変換に失敗しました。'
理由:EntityFramework Coreが('0001-01-01T00:00:00.0000000'.
ではなく'1753-01-01T00:00:00.000'
)間違ったデフォルト値を使用している:
SELECT [post].[Id], [post].[Subject], COALESCE((
SELECT TOP(1) [relation.Category].[Created]
FROM [PostCategory] AS [relation]
INNER JOIN [Categories] AS [relation.Category] ON [relation].[CategoryId] = [relation.Category].[Id]
WHERE [post].[Id] = [relation].[PostId]
ORDER BY [relation.Category].[Created] DESC
), '0001-01-01T00:00:00.0000000') AS [latestCategoryTimestamp]
FROM [Posts] AS [post]
既存のデータベースに触れずに修正するにはどうすればよいですか?
ちなみに、OnModelCreating()
足場はしっかりしています:
modelBuilder.Entity<Categories>(entity =>
{
entity.Property(e => e.Created).HasColumnType("datetime");
//...
});
EF Coreのバグのように見えるかもしれませんが、私にはそれは間違ったクエリのようです。
EF Coreが、CLRのDateTime
デフォルトをSqlServerの最小サポート日に「正しく」変換することを想像してみてください。マテリアライズされた結果が得られたら、それlatestCategoryTimestamp
がデフォルトかどうかをどのようにして知ることができますか?SqlServerの最小日付と照合していますか?インメモリデータベースまたはその他のデータベースに対してクエリを実行している場合はどうなりますか?彼らはそれをメモリに戻す必要があると言うかもしれませんか?データベースの最小値をマップする必要があるのはなぜdefault(DateTime)
ですか?ではどうDateTime.MinValue
ですか?
結論は、の正しいマッピングがないということですdefault(DateTime)
。問題は、なぜ「魔法の」値を使用して欠落値を表すのかということです。データベースはそれを提供NULL
し、C#(CLR)-null許容型です。
したがって、最も論理的な方法はnull許容型を使用することです。クエリで変更する必要があるのは、DateTime?
ここにキャストを追加することだけです
select (DateTime?)relation.Category.Created
ただし、ここで必要なのは最大日付だけなので、Max
メソッドを使用するだけで十分です(ただし、null許容のオーバーロードを使用します)。
let latestCategoryTimestamp = post.PostCategory.Max(link => (DateTime?)link.Category.Created)
ただし、どのアプローチを選択した場合でも、必要なのNullable<DateTime>
は、マテリアライズされたオブジェクトのプロパティを考慮することだけです。良い点はnull
、データベースの種類に関係なく、が欠落している投稿カテゴリを示すことです。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加