엔티티 프레임워크 MariaDb 문자열 날짜 문제
EF core와 MariaDb 데이터베이스에 문제가 있는 것 같습니다.우선, 데이터베이스를 조금 변경하는 명백한 움직임은 할 수 없기 때문에, 그 옵션은 사용할 수 없습니다.
연락처 날짜가 보관되어 있는 "연락처" 테이블이 있습니다.이 연락처 날짜는 날짜만 포함하는 문자열 값 형식으로 보관됩니다. 즉, 2020년 8월 30일의 2020-08-30입니다.이 필드의 EF 코어 매핑은 다음과 같습니다.
entity.Property(e => e.ContactDate)
.IsRequired()
.HasColumnName("contactDate")
.HasColumnType("varchar(255)")
여기서 e.ContactDate는 DateTime 속성입니다.
코드의 속성을 사용하면 날짜/시간이 예상대로 작동하며 데이터뱅크에 저장된 날짜가 포함됩니다.만세!
그러나 이 문제는 해당 날짜에 쿼리할 때 발생합니다.이 쿼리가 지정되면:
SELECT `c7`.`contactDate`
FROM `contacts` AS `c7`
WHERE (`f`.`uuid` = `c7`.`fileUuid`) AND (`c7`.`numberOfContacts` > 0)
ORDER BY `c7`.`contactDate`
LIMIT 1) <= @__endDate_1) AND (`f`.`closingDate` IS NULL OR ((`f`.`closingDate` >= @__startDate_2)
및 startDate "endDate"로 됩니다.를 들어, 「」라고 하는 것은,@__endDate_1='2019-12-31 00:00:00'
그리고 여기에 문제가 있습니다.MySql ® contactDate db endDate > endDate > 。을사용하다SELECT "2020-02-04" >= "2020-02-04 00:00:00"
이 0은 0입니다.
제가 할 수 있는 방법이 있나요?
- 또는 모든 쿼리에서 contactDate를 타임스탬프가 있는 값으로 캐스팅하는 EF를 변경합니다.
- 아니면 시간 값 없이 날짜 값을 날짜 값으로 캐스팅하는 EF를 변경하시겠습니까?
EF의 DateTime to Date 문자열 래퍼로 새로운 "Date" 클래스를 도입하는 세 번째 솔루션에 대해 어떻게 생각하십니까?
감사합니다!
와 함께
.HasColumnType("varchar(255)")
EF Core 내장 DateTime을 문자열 값 변환기로 활성화하고 있습니다.문서화된 것은 아니지만, 이 정보는DateTime
명령어 때을 에(를) 설정합니다.string
다음 형식(또는 유사한 형식)을 사용합니다.
"yyyy\\-MM\\-dd HH\\:mm\\:ss.FFFFFFF"
필요한 것은 이런 형식입니다.
"yyyy\\-MM\\-dd"
커스텀 값 컨버터를 설정하면 다음과 같이 할 수 있습니다.
entity.Property(e => e.ContactDate)
.HasConversion(
value => value.ToString("yyyy\\-MM\\-dd"),
dbValue => DateTime.Parse(dbValue, CultureInfo.InvariantCulture)
)
// the rest is the same
.IsRequired()
.HasColumnName("contactDate")
.HasColumnType("varchar(255)"); // or .IsUnicode(false).HasMaxLength(255)
이치노는 「」가 됩니다.@__endDate_1='2019-12-31'
2번입니다.
글머리 기호 #1은 불가능합니다.
한 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★Date
유형은 가능하지만, 많은 인프라 배관 코드가 필요하기 때문에 쉽지는 않습니다.노다 시간, 넷토폴로지관심 있으면 그 실장을 볼 수 있지만 IMHO는 (간단한) 커스텀 밸류 타입을 지원하는 것이 EF Core 우선 사항이 아니기 때문에 (현재는) 더 나은 지원을 받을 때까지 가치 변환기를 계속 사용하고 싶습니다.
@IvanStoev의 답변은 요청대로, 예상대로 작동합니다.
동작하고 있는 콘솔 프로그램의 예를 다음에 나타냅니다.
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Storage;
namespace IssueConsoleTemplate
{
public class Contact
{
public int ContactId { get; set; }
public DateTime ContactDate { get; set; }
}
public class Context : DbContext
{
public virtual DbSet<Contact> Contacts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseMySql("server=127.0.0.1;port=3306;user=root;password=;database=So63655418",
b => b
.ServerVersion(new ServerVersion("8.0.20-mysql")))
.UseLoggerFactory(LoggerFactory.Create(b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>(
entity =>
{
entity.Property(e => e.ContactDate)
.HasColumnType("varchar(255)")
.HasConversion(
v => v.ToString(@"yyyy\-MM\-dd"),
v => DateTime.Parse(v, CultureInfo.InvariantCulture));
entity.HasData(
new Contact
{
ContactId = 1,
ContactDate = new DateTime(2020, 9, 1, 14, 42, 59, 123), // <-- time will be dropped
});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var dateParameter = new DateTime(2020, 9, 1, 21, 11, 1, 456); // <-- time will be dropped
var contactWithExactDate = context.Contacts.SingleOrDefault(c => c.ContactDate == dateParameter);
Debug.Assert(contactWithExactDate != null);
Debug.Assert(contactWithExactDate.ContactDate == new DateTime(2020, 9, 1));
}
}
}
다음 SQL 문을 생성합니다.
warn: Microsoft.EntityFrameworkCore.Model.Validation[10400]
Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data, this mode should only be enabled during development.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.1.8 initialized 'Context' using provider 'Pomelo.EntityFrameworkCore.MySql' with options: ServerVersion 8.0.20 MySql SensitiveDataLoggingEnabled DetailedErrorsEnabled
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (77ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
DROP DATABASE `So63655418`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (11ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE DATABASE `So63655418`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (70ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE `Contacts` (
`ContactId` int NOT NULL AUTO_INCREMENT,
`ContactDate` varchar(255) NOT NULL,
CONSTRAINT `PK_Contacts` PRIMARY KEY (`ContactId`)
);
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (11ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
INSERT INTO `Contacts` (`ContactId`, `ContactDate`)
VALUES (1, '2020-09-01');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (8ms) [Parameters=[@__dateParameter_0='2020-09-01' (Nullable = false) (Size = 255)], CommandType='Text', CommandTimeout='30']
SELECT `c`.`ContactId`, `c`.`ContactDate`
FROM `Contacts` AS `c`
WHERE `c`.`ContactDate` = @__dateParameter_0
LIMIT 2
프로그램은 어설션 없이 실행되며 로그에 기록된 SQL 문은 사용된 파라미터를 올바르게 나타냅니다.@__dateParameter_0='2020-09-01'
C# 코드에 시간 값을 명시적으로 사용했는데도 말이죠.
당신이 작성한 대로 포맷을 데이터베이스에 남겼을 거예요.하지만 나는 질문을 바꿨을 것이다.이 경우 이 스레드에 표시된 것과 같은 날짜 형식의 캐스트:
MySQL DATETIME 필드의 문자열과 DATETIME 비교
SELECT * FROM contacts WHERE DATE(startTime) > '2020-08-30'
...또는 MariaDB 공식 문서: DATETIME 구문
답변을 기다리는 시간이 길었을 때 날짜 유형 접근 방식을 사용하여 특정 변환을 시도했습니다.기적적으로 EF는 저장된 모든 문자열 날짜를 쿼리에서 datetime 개체로 변환했습니다.정말 훌륭했고, 성공했어요!
내 날짜 개체의 코드입니다.
public struct Date: IComparable<Date>, IComparable<DateTime>, IComparable, IEquatable<Date>
{
/// <summary>
/// Turns a DateTime into a Date
/// </summary>
/// <param name="dateTime"></param>
public Date(DateTime dateTime)
{
_date = dateTime.Date;
}
private readonly DateTime _date;
public static implicit operator Date(DateTime value) => new Date(value);
public static implicit operator DateTime(Date value) => value._date;
public int CompareTo(Date other) => _date.CompareTo(other._date);
public int CompareTo(DateTime other) => _date.CompareTo(new Date(other));
public int CompareTo(object obj) => _date.CompareTo(obj);
public bool Equals(Date other) => _date.Equals(other._date);
public override bool Equals(object obj) => obj is Date other && Equals(other);
public override int GetHashCode() => _date.GetHashCode();
}
EF로의 전환은 다음과 같습니다.
public static PropertyBuilder<Date?> HasDateConversion(this PropertyBuilder<Date?> propertyBuilder) =>
propertyBuilder
.HasConversion(date =>
date.HasValue
? ParseDate(date.Value)
: null,
str =>
string.IsNullOrWhiteSpace(str)
? null
: (Date?)ParseString(str));
그 결과 선택한 모든 날짜가 다음과 같이 선택되었습니다.
SELECT * FROM `contacts` AS `c`
WHERE CAST(`c`.`contactDate` AS datetime(6)) < '2020-01-03 05:01:03.000000'
LIMIT 1
이렇게 해서 나의 문제는 해결되었다:) 만세!
언급URL : https://stackoverflow.com/questions/63655418/entity-framework-mariadb-date-as-string-problem
'it-source' 카테고리의 다른 글
'mysqldump'를 사용하여 CSV 형식의 모든 테이블 덤프 (0) | 2022.12.19 |
---|---|
vue에서 sass 변수를 재정의하려면 어떻게 해야 합니까? (0) | 2022.12.19 |
동일한 서버에서 MySQL 데이터베이스를 복제하는 방법 (0) | 2022.12.19 |
부모 POM에서 상속받은 아티팩트를 제외할 수 있는 방법이 있습니까? (0) | 2022.12.19 |
크리스마스 트리는 어떻게 감지하나요? (0) | 2022.12.19 |