-
Notifications
You must be signed in to change notification settings - Fork 3.3k
[rc2] SQLite: Make AUTOINCREMENT first-class and fix false pending model changes warning for value converters #36717
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
32293b1
fa6fbfe
a9b7973
738d27f
a1ab3b0
21c588b
2698227
e84ae21
e0087b5
da1ebe3
ca03cda
fdb1536
665a925
219a91c
e533351
3769a12
28412a4
2b52a6b
0754086
37f6338
9685d43
050c685
1de78ab
b371842
a34ef8b
a0a0eb1
744c2c3
eaf05a2
f48a50f
782762c
a4919ca
388c332
85b9a3d
f2e7f0f
e337cac
b2e736e
c90161c
786542b
5e04e23
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Diagnostics.CodeAnalysis; | ||
using Microsoft.EntityFrameworkCore.Sqlite.Metadata.Internal; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Sqlite.Design.Internal; | ||
|
||
/// <summary> | ||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to | ||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in | ||
/// any release. You should only use it directly in your code with extreme caution and knowing that | ||
/// doing so can result in application failures when updating to a new Entity Framework Core release. | ||
/// </summary> | ||
public class SqliteAnnotationCodeGenerator : AnnotationCodeGenerator | ||
{ | ||
#region MethodInfos | ||
|
||
private static readonly MethodInfo PropertyUseAutoincrementMethodInfo | ||
= typeof(SqlitePropertyBuilderExtensions).GetRuntimeMethod( | ||
nameof(SqlitePropertyBuilderExtensions.UseAutoincrement), [typeof(PropertyBuilder)])!; | ||
|
||
private static readonly MethodInfo ComplexTypePropertyUseAutoincrementMethodInfo | ||
= typeof(SqliteComplexTypePropertyBuilderExtensions).GetRuntimeMethod( | ||
nameof(SqliteComplexTypePropertyBuilderExtensions.UseAutoincrement), [typeof(ComplexTypePropertyBuilder)])!; | ||
|
||
#endregion MethodInfos | ||
|
||
/// <summary> | ||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to | ||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in | ||
/// any release. You should only use it directly in your code with extreme caution and knowing that | ||
/// doing so can result in application failures when updating to a new Entity Framework Core release. | ||
/// </summary> | ||
public SqliteAnnotationCodeGenerator(AnnotationCodeGeneratorDependencies dependencies) | ||
: base(dependencies) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to | ||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in | ||
/// any release. You should only use it directly in your code with extreme caution and knowing that | ||
/// doing so can result in application failures when updating to a new Entity Framework Core release. | ||
/// </summary> | ||
public override IReadOnlyList<MethodCallCodeFragment> GenerateFluentApiCalls( | ||
IProperty property, | ||
IDictionary<string, IAnnotation> annotations) | ||
{ | ||
var fragments = new List<MethodCallCodeFragment>(base.GenerateFluentApiCalls(property, annotations)); | ||
|
||
if (TryGetAndRemove<SqliteValueGenerationStrategy>(annotations, SqliteAnnotationNames.ValueGenerationStrategy, out var strategy) | ||
&& strategy == SqliteValueGenerationStrategy.Autoincrement) | ||
{ | ||
var methodInfo = property.DeclaringType is IComplexType | ||
? ComplexTypePropertyUseAutoincrementMethodInfo | ||
: PropertyUseAutoincrementMethodInfo; | ||
fragments.Add(new MethodCallCodeFragment(methodInfo)); | ||
} | ||
|
||
return fragments; | ||
} | ||
|
||
/// <summary> | ||
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to | ||
/// the same compatibility standards as public APIs. It may be changed or removed without notice in | ||
/// any release. You should only use it directly in your code with extreme caution and knowing that | ||
/// doing so can result in application failures when updating to a new Entity Framework Core release. | ||
/// </summary> | ||
protected override bool IsHandledByConvention(IProperty property, IAnnotation annotation) | ||
{ | ||
if (annotation.Name == SqliteAnnotationNames.ValueGenerationStrategy) | ||
{ | ||
return (SqliteValueGenerationStrategy)annotation.Value! == property.GetDefaultValueGenerationStrategy(); | ||
} | ||
|
||
return base.IsHandledByConvention(property, annotation); | ||
} | ||
|
||
private static bool TryGetAndRemove<T>( | ||
IDictionary<string, IAnnotation> annotations, | ||
string annotationName, | ||
[NotNullWhen(true)] out T? annotationValue) | ||
{ | ||
if (annotations.TryGetValue(annotationName, out var annotation) | ||
&& annotation.Value != null) | ||
{ | ||
annotations.Remove(annotationName); | ||
annotationValue = (T)annotation.Value; | ||
return true; | ||
} | ||
|
||
annotationValue = default; | ||
return false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
namespace Microsoft.EntityFrameworkCore.Diagnostics; | ||
|
||
/// <summary> | ||
/// A <see cref="DiagnosticSource" /> event payload class for events that have | ||
/// conflicting value generation strategies. | ||
/// </summary> | ||
/// <remarks> | ||
/// See <see href="https://aka.ms/efcore-docs-diagnostics">Logging, events, and diagnostics</see>, and | ||
/// <see href="https://aka.ms/efcore-docs-sqlite">Accessing SQLite databases with EF Core</see> | ||
/// for more information and examples. | ||
/// </remarks> | ||
public class ConflictingValueGenerationStrategiesEventData : EventData | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we sure we really need a whole new heavy event + event data here? IIUC this is only for the case where the user misconfigures their model - we usually just do a simple warning (or even just throw), shouldn't we do this here? Is there a case where it makes sense for the user to actually configure a property with conflicting value generation strategies (and suppress this)? (I can see that SQL Server has this too, but I'm trying to understand why we need it) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is mostly to avoid breaking changes. |
||
{ | ||
/// <summary> | ||
/// Constructs the event payload. | ||
/// </summary> | ||
/// <param name="eventDefinition">The event definition.</param> | ||
/// <param name="messageGenerator">A delegate that generates a log message for this event.</param> | ||
/// <param name="sqliteValueGenerationStrategy">The SQLite value generation strategy.</param> | ||
/// <param name="otherValueGenerationStrategy">The other value generation strategy.</param> | ||
/// <param name="property">The property.</param> | ||
public ConflictingValueGenerationStrategiesEventData( | ||
EventDefinitionBase eventDefinition, | ||
Func<EventDefinitionBase, EventData, string> messageGenerator, | ||
SqliteValueGenerationStrategy sqliteValueGenerationStrategy, | ||
string otherValueGenerationStrategy, | ||
IReadOnlyProperty property) | ||
: base(eventDefinition, messageGenerator) | ||
{ | ||
SqliteValueGenerationStrategy = sqliteValueGenerationStrategy; | ||
OtherValueGenerationStrategy = otherValueGenerationStrategy; | ||
Property = property; | ||
} | ||
|
||
/// <summary> | ||
/// The SQLite value generation strategy. | ||
/// </summary> | ||
public virtual SqliteValueGenerationStrategy SqliteValueGenerationStrategy { get; } | ||
|
||
/// <summary> | ||
/// The other value generation strategy. | ||
/// </summary> | ||
public virtual string OtherValueGenerationStrategy { get; } | ||
|
||
/// <summary> | ||
/// The property. | ||
/// </summary> | ||
public virtual IReadOnlyProperty Property { get; } | ||
} |
Uh oh!
There was an error while loading. Please reload this page.