Skip to content

Commit 550d80f

Browse files
updates
1 parent 021270b commit 550d80f

File tree

15 files changed

+328
-111
lines changed

15 files changed

+328
-111
lines changed

src/EFCore.Ydb/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
- Fixed bug: Error when saving an entity without specifying a default value ()
12
- Fixed bug: SqlQuery throws exception when using list parameters ([#540](https://github.com/ydb-platform/ydb-dotnet-sdk/issues/540)).
23
- Added support for the YDB retry policy (ADO.NET) and new configuration methods in `YdbDbContextOptionsBuilder`:
34
- `EnableRetryIdempotence()`: enables retries for errors classified as idempotent. You must ensure the operation itself is idempotent.

src/EFCore.Ydb/src/Metadata/Conventions/YdbConventionSetBuilder.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ public override ConventionSet CreateConventionSet()
1313
{
1414
var coreConventions = base.CreateConventionSet();
1515
coreConventions.Add(new YdbStringAttributeConvention(Dependencies));
16-
coreConventions.Add(new YdbValueGenerationConvention(Dependencies, RelationalDependencies));
1716
return coreConventions;
1817
}
1918
}

src/EFCore.Ydb/src/Metadata/Conventions/YdbValueGenerationConvention.cs

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/EFCore.Ydb/src/Migrations/Internal/YdbHistoryRepository.cs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public override async Task<IMigrationsDatabaseLock> AcquireDatabaseLockAsync(
4545
{
4646
await Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync(
4747
AcquireDatabaseLockCommand(),
48-
((IYdbRelationalConnection)Dependencies.Connection).Clone(), // TODO usage ExecutionContext
48+
Dependencies.Connection,
4949
new MigrationExecutionState(),
5050
commitTransaction: true,
5151
cancellationToken: cancellationToken
@@ -85,9 +85,7 @@ private async Task ReleaseDatabaseLockAsync()
8585
try
8686
{
8787
await Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync(
88-
ReleaseDatabaseLockCommand(),
89-
((IYdbRelationalConnection)Dependencies.Connection).Clone()
90-
).ConfigureAwait(false);
88+
ReleaseDatabaseLockCommand(), Dependencies.Connection).ConfigureAwait(false);
9189

9290
return;
9391
}
@@ -98,10 +96,8 @@ await Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync(
9896
}
9997
}
10098

101-
private IReadOnlyList<MigrationCommand> ReleaseDatabaseLockCommand() =>
102-
Dependencies.MigrationsSqlGenerator.Generate(new List<MigrationOperation>
103-
{ new SqlOperation { Sql = GetDeleteScript(LockKey) } }
104-
);
99+
private IReadOnlyList<MigrationCommand> ReleaseDatabaseLockCommand() => Dependencies.MigrationsSqlGenerator
100+
.Generate(new List<MigrationOperation> { new SqlOperation { Sql = GetDeleteScript(LockKey) } });
105101

106102
bool IHistoryRepository.CreateIfNotExists() => CreateIfNotExistsAsync().GetAwaiter().GetResult();
107103

@@ -135,13 +131,7 @@ await Dependencies.MigrationCommandExecutor.ExecuteNonQueryAsync(
135131

136132
private IReadOnlyList<MigrationCommand> GetCreateIfNotExistsCommands() =>
137133
Dependencies.MigrationsSqlGenerator.Generate(new List<MigrationOperation>
138-
{
139-
new SqlOperation
140-
{
141-
Sql = GetCreateIfNotExistsScript(),
142-
SuppressTransaction = true
143-
}
144-
});
134+
{ new SqlOperation { Sql = GetCreateIfNotExistsScript(), SuppressTransaction = true } });
145135

146136
public override string GetCreateIfNotExistsScript()
147137
=> GetCreateScript().Replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");
@@ -179,8 +169,8 @@ private IReadOnlyList<MigrationCommand> SelectHistoryTableCommand() =>
179169
{
180170
new SqlOperation
181171
{
182-
Sql = $"SELECT * FROM {SqlGenerationHelper.DelimitIdentifier(TableName, TableSchema)}" +
183-
$" WHERE '{MigrationIdColumnName}' = '{LockKey}';"
172+
Sql = $"SELECT * FROM {SqlGenerationHelper.DelimitIdentifier(TableName, TableSchema)} " +
173+
$"WHERE '{MigrationIdColumnName}' = CAST(RandomUuid(0) AS Text)"
184174
}
185175
});
186176

src/EFCore.Ydb/src/Migrations/YdbMigrationsSqlGenerator.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ MigrationCommandListBuilder builder
8181
.Append(" ")
8282
.Append(columnType)
8383
.Append(operation.IsNullable ? string.Empty : " NOT NULL");
84+
85+
if (autoincrement == true)
86+
return;
87+
88+
DefaultValue(operation.DefaultValue, operation.DefaultValueSql, columnType, builder);
8489
}
8590

8691
protected override void CreateTablePrimaryKeyConstraint(
Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,21 @@
11
using System;
2-
using Microsoft.EntityFrameworkCore.Storage;
2+
using Ydb.Sdk.Ado.YdbType;
33

44
namespace EntityFrameworkCore.Ydb.Storage.Internal.Mapping;
55

6-
// TODO: Await DateOnly support in Ydb.Sdk
7-
public class YdbDateOnlyTypeMapping : RelationalTypeMapping
6+
public class YdbDateOnlyTypeMapping : YdbTypeMapping
87
{
9-
private const string DateOnlyFormatConst = "{0:yyyy-MM-dd}";
10-
11-
public YdbDateOnlyTypeMapping(string storeType)
12-
: base(
13-
new RelationalTypeMappingParameters(
14-
new CoreTypeMappingParameters(typeof(DateOnly)),
15-
storeType,
16-
StoreTypePostfix.None,
17-
System.Data.DbType.Date
18-
)
19-
)
8+
public YdbDateOnlyTypeMapping(YdbDbType ydbDbType) : base(typeof(DateOnly), ydbDbType)
209
{
2110
}
2211

23-
protected YdbDateOnlyTypeMapping(RelationalTypeMappingParameters parameters) : base(parameters)
12+
private YdbDateOnlyTypeMapping(RelationalTypeMappingParameters parameters, YdbDbType ydbDbType)
13+
: base(parameters, ydbDbType)
2414
{
2515
}
2616

27-
protected override YdbDateOnlyTypeMapping Clone(RelationalTypeMappingParameters parameters) => new(parameters);
17+
protected override YdbDateOnlyTypeMapping Clone(RelationalTypeMappingParameters parameters) =>
18+
new(parameters, YdbDbType);
2819

29-
protected override string GenerateNonNullSqlLiteral(object value)
30-
{
31-
var dateOnly = (DateOnly)value;
32-
return $"Date('{dateOnly.ToString(DateOnlyFormatConst)}')";
33-
}
20+
protected override string SqlLiteralFormatString => $"{YdbDbType}('{{0:yyyy-MM-dd}}')";
3421
}
Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1-
using System.Data;
2-
using Microsoft.EntityFrameworkCore.Storage;
1+
using System;
2+
using Ydb.Sdk.Ado.YdbType;
33

44
namespace EntityFrameworkCore.Ydb.Storage.Internal.Mapping;
55

6-
public class YdbDateTimeTypeMapping(
7-
string storeType,
8-
DbType? dbType
9-
) : DateTimeTypeMapping(storeType, dbType)
6+
public class YdbDateTimeTypeMapping : YdbTypeMapping
107
{
11-
private const string DateTimeFormatConst = @"{0:yyyy-MM-dd HH\:mm\:ss.fffffff}";
8+
public YdbDateTimeTypeMapping(YdbDbType ydbDbType) : base(typeof(DateTime), ydbDbType)
9+
{
10+
}
1211

13-
private string StoreTypeLiteral { get; } = storeType;
12+
private YdbDateTimeTypeMapping(RelationalTypeMappingParameters parameters, YdbDbType ydbDbType)
13+
: base(parameters, ydbDbType)
14+
{
15+
}
1416

15-
protected override string SqlLiteralFormatString
16-
=> "CAST('" + DateTimeFormatConst + $"' AS {StoreTypeLiteral})";
17+
protected override YdbDateTimeTypeMapping Clone(RelationalTypeMappingParameters parameters) =>
18+
new(parameters, YdbDbType);
19+
20+
protected override string SqlLiteralFormatString => YdbDbType switch
21+
{
22+
YdbDbType.Timestamp or YdbDbType.Timestamp64 => $@"{YdbDbType}('{{0:yyyy-MM-ddTHH\:mm\:ss.ffffffZ}}')",
23+
YdbDbType.Datetime or YdbDbType.Datetime64 => $@"{YdbDbType}('{{0:yyyy-MM-ddTHH\:mm\:ssZ}}')",
24+
YdbDbType.Date or YdbDbType.Date32 => $"{YdbDbType}('{{0:yyyy-MM-dd}}')",
25+
_ => throw new ArgumentOutOfRangeException(nameof(YdbDbType), YdbDbType, null)
26+
};
1727
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Xml;
3+
using Ydb.Sdk.Ado.YdbType;
4+
5+
namespace EntityFrameworkCore.Ydb.Storage.Internal.Mapping;
6+
7+
public class YdbTimeSpanTypeMapping : YdbTypeMapping
8+
{
9+
public YdbTimeSpanTypeMapping(YdbDbType ydbDbType) : base(typeof(TimeSpan), ydbDbType)
10+
{
11+
}
12+
13+
private YdbTimeSpanTypeMapping(RelationalTypeMappingParameters parameters, YdbDbType ydbDbType)
14+
: base(parameters, ydbDbType)
15+
{
16+
}
17+
18+
protected override YdbTimeSpanTypeMapping Clone(RelationalTypeMappingParameters parameters) =>
19+
new(parameters, YdbDbType);
20+
21+
protected override string GenerateNonNullSqlLiteral(object value) =>
22+
$"{YdbDbType}('{XmlConvert.ToString((TimeSpan)value)}')";
23+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Data.Common;
3+
using Microsoft.EntityFrameworkCore.Storage;
4+
using Microsoft.EntityFrameworkCore.Storage.Json;
5+
using Ydb.Sdk.Ado;
6+
using Ydb.Sdk.Ado.YdbType;
7+
8+
namespace EntityFrameworkCore.Ydb.Storage.Internal.Mapping;
9+
10+
public abstract class YdbTypeMapping(
11+
RelationalTypeMapping.RelationalTypeMappingParameters parameters,
12+
YdbDbType ydbDbType
13+
) : RelationalTypeMapping(parameters), IYdbTypeMapping
14+
{
15+
public YdbDbType YdbDbType { get; } = ydbDbType;
16+
17+
protected YdbTypeMapping(
18+
Type clrType,
19+
YdbDbType ydbDbType,
20+
JsonValueReaderWriter? jsonValueReaderWriter = null
21+
) : this(
22+
new RelationalTypeMappingParameters(
23+
new CoreTypeMappingParameters(clrType, jsonValueReaderWriter: jsonValueReaderWriter),
24+
ydbDbType.ToString()
25+
), ydbDbType
26+
)
27+
{
28+
}
29+
30+
protected override void ConfigureParameter(DbParameter parameter)
31+
{
32+
if (parameter is not YdbParameter npgsqlParameter)
33+
{
34+
throw new InvalidOperationException(
35+
$"Ydb-specific type mapping {GetType().Name} being used with non-Ydb parameter type {parameter.GetType().Name}");
36+
}
37+
38+
base.ConfigureParameter(parameter);
39+
npgsqlParameter.YdbDbType = YdbDbType;
40+
}
41+
}

src/EFCore.Ydb/src/Storage/Internal/YdbTypeMappingSource.cs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,26 @@ RelationalTypeMappingSourceDependencies relationalDependencies
3838

3939
private static readonly YdbDecimalTypeMapping Decimal = YdbDecimalTypeMapping.Default;
4040

41-
private static readonly GuidTypeMapping Guid = YdbGuidTypeMapping.Default;
41+
private static readonly GuidTypeMapping Uuid = YdbGuidTypeMapping.Default;
4242

4343
private static readonly YdbTextTypeMapping Text = YdbTextTypeMapping.Default;
4444
private static readonly YdbBytesTypeMapping Bytes = YdbBytesTypeMapping.Default;
4545
private static readonly YdbJsonTypeMapping Json = new("Json", typeof(JsonElement), null);
4646

47-
private static readonly YdbDateOnlyTypeMapping Date = new("Date");
48-
private static readonly DateTimeTypeMapping DateTime = new("DateTime");
47+
private static readonly YdbDateOnlyTypeMapping DateDateOnly = new(YdbDbType.Date);
48+
private static readonly YdbDateOnlyTypeMapping Date32DateOnly = new(YdbDbType.Date32);
4949

50-
private static readonly YdbDateTimeTypeMapping Timestamp = new("Timestamp", DbType.DateTime);
50+
private static readonly YdbDateTimeTypeMapping DateDateTime = new(YdbDbType.Date);
51+
private static readonly YdbDateTimeTypeMapping Date32DateTime = new(YdbDbType.Date32);
5152

52-
// TODO: Await interval in Ydb.Sdk
53-
private static readonly TimeSpanTypeMapping Interval = new("Interval", DbType.Object);
53+
private static readonly YdbDateTimeTypeMapping Datetime = new(YdbDbType.Datetime);
54+
private static readonly YdbDateTimeTypeMapping Datetime64 = new(YdbDbType.Datetime64);
55+
56+
private static readonly YdbDateTimeTypeMapping Timestamp = new(YdbDbType.Timestamp);
57+
private static readonly YdbDateTimeTypeMapping Timestamp64 = new(YdbDbType.Timestamp64);
58+
59+
private static readonly YdbTimeSpanTypeMapping Interval = new(YdbDbType.Interval);
60+
private static readonly YdbTimeSpanTypeMapping Interval64 = new(YdbDbType.Interval64);
5461

5562
#endregion
5663

@@ -72,17 +79,20 @@ RelationalTypeMappingSourceDependencies relationalDependencies
7279
{ "Float", [Float] },
7380
{ "Double", [Double] },
7481

75-
{ "Guid", [Guid] },
76-
77-
{ "Date", [Date] },
78-
{ "DateTime", [DateTime] },
79-
{ "Timestamp", [Timestamp] },
80-
{ "Interval", [Interval] },
82+
{ "Guid", [Uuid] },
8183

8284
{ "Text", [Text] },
8385
{ "Bytes", [Bytes] },
8486

85-
{ "Json", [Json] }
87+
{ "Date", [DateDateTime, DateDateOnly] },
88+
{ "DateTime", [Datetime] },
89+
{ "Timestamp", [Timestamp] },
90+
{ "Interval", [Interval] },
91+
92+
{ "Date32", [Date32DateTime, Date32DateOnly] },
93+
{ "Datetime64", [Datetime64] },
94+
{ "Timestamp64", [Timestamp64] },
95+
{ "Interval64", [Interval64] }
8696
};
8797

8898
private static readonly Dictionary<Type, RelationalTypeMapping> ClrTypeMapping = new()
@@ -102,13 +112,13 @@ RelationalTypeMappingSourceDependencies relationalDependencies
102112
{ typeof(float), Float },
103113
{ typeof(double), Double },
104114

105-
{ typeof(Guid), Guid },
115+
{ typeof(Guid), Uuid },
106116

107117
{ typeof(string), Text },
108118
{ typeof(byte[]), Bytes },
109119
{ typeof(JsonElement), Json },
110120

111-
{ typeof(DateOnly), Date },
121+
{ typeof(DateOnly), DateDateOnly },
112122
{ typeof(DateTime), Timestamp },
113123
{ typeof(TimeSpan), Interval }
114124
};

0 commit comments

Comments
 (0)