mirror of
https://github.com/fergalmoran/EFCore.NamingConventions.git
synced 2025-12-22 01:28:13 +00:00
Initial commit
This commit is contained in:
40
.editorconfig
Normal file
40
.editorconfig
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
; Top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
; Unix-style newlines
|
||||||
|
[*]
|
||||||
|
end_of_line = LF
|
||||||
|
|
||||||
|
; 4-column space indentation
|
||||||
|
[*.cs]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
; trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.cs]
|
||||||
|
dotnet_style_qualification_for_field = false:error
|
||||||
|
dotnet_style_qualification_for_property = false:error
|
||||||
|
dotnet_style_qualification_for_method = false:error
|
||||||
|
dotnet_style_qualification_for_event = false:error
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true:error
|
||||||
|
dotnet_style_predefined_type_for_member_access = true:error
|
||||||
|
dotnet_style_object_initializer = true:suggestion
|
||||||
|
dotnet_style_collection_initializer = true:suggestion
|
||||||
|
dotnet_style_explicit_tuple_names = true:suggestion
|
||||||
|
dotnet_style_coalesce_expression = true:suggestion
|
||||||
|
csharp_style_var_for_built_in_types = true:error
|
||||||
|
csharp_style_var_when_type_is_apparent = true:error
|
||||||
|
csharp_style_var_elsewhere = true:suggestion
|
||||||
|
csharp_style_expression_bodied_methods = true:suggestion
|
||||||
|
csharp_style_expression_bodied_constructors = true:suggestion
|
||||||
|
csharp_style_expression_bodied_operators = true:suggestion
|
||||||
|
csharp_style_expression_bodied_properties = true:suggestion
|
||||||
|
csharp_style_expression_bodied_indexers = true:suggestion
|
||||||
|
csharp_style_expression_bodied_accessors = true:suggestion
|
||||||
|
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||||
|
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||||
|
csharp_style_inlined_variable_declaration = true:suggestion
|
||||||
|
csharp_style_throw_expression = true:suggestion
|
||||||
|
csharp_style_conditional_delegate_call = true:suggestion
|
||||||
|
csharp_indent_case_contents_when_block = false
|
||||||
10
.gitattributes
vendored
Normal file
10
.gitattributes
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
* text=auto
|
||||||
|
|
||||||
|
*.cs text=auto diff=csharp
|
||||||
|
*.csproj text=auto
|
||||||
|
*.sln text=auto
|
||||||
|
*.resx text=auto
|
||||||
|
*.xml text=auto
|
||||||
|
*.txt text=auto
|
||||||
|
|
||||||
|
packages/ binary
|
||||||
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
.DS_Store
|
||||||
|
*.resources
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.sln.docstates
|
||||||
|
*.userprefs
|
||||||
|
/*.nupkg
|
||||||
|
.nuget/
|
||||||
|
.idea/
|
||||||
|
[Bb]in/
|
||||||
|
[Bb]uild/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]bj/
|
||||||
|
packages/*/
|
||||||
|
Packages/*/
|
||||||
|
packages.stable
|
||||||
|
artifacts/
|
||||||
|
# Roslyn cache directories
|
||||||
|
*.ide/
|
||||||
|
.vs/
|
||||||
|
TestResult.xml
|
||||||
13
Directory.Build.props
Normal file
13
Directory.Build.props
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<Project>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<LangVersion>8.0</LangVersion>
|
||||||
|
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Label="Package Versions">
|
||||||
|
<EFCoreVersion>3.0.0-preview9.19423.6</EFCoreVersion>
|
||||||
|
<MicrosoftExtensionsVersion>3.0.0-preview9.19423.4</MicrosoftExtensionsVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(EFCoreVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\EFCore.NamingConventions\EFCore.NamingConventions.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
41
EFCore.NamingConventions.Test/NamingConventionsTest.cs
Normal file
41
EFCore.NamingConventions.Test/NamingConventionsTest.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace EFCore.Naming.Test
|
||||||
|
{
|
||||||
|
public class NamingTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Table_name_is_rewritten()
|
||||||
|
{
|
||||||
|
using var context = new TestContext();
|
||||||
|
var entityType = context.Model.FindEntityType(typeof(Blog));
|
||||||
|
Assert.Equal("blog", entityType.GetTableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Column_name_is_rewritten()
|
||||||
|
{
|
||||||
|
using var context = new TestContext();
|
||||||
|
var entityType = context.Model.FindEntityType(typeof(Blog));
|
||||||
|
Assert.Equal("id", entityType.FindProperty("Id").GetColumnName());
|
||||||
|
Assert.Equal("full_name", entityType.FindProperty("FullName").GetColumnName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<Blog> Blog { get; set; }
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
=> optionsBuilder
|
||||||
|
.UseInMemoryDatabase("test")
|
||||||
|
.UseSnakeCaseNamingConventions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Blog
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string FullName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
EFCore.NamingConventions.sln
Normal file
24
EFCore.NamingConventions.sln
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFCore.NamingConventions", "EFCore.NamingConventions\EFCore.NamingConventions.csproj", "{F7AE70A6-D237-4257-84F4-A32375E78E10}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFCore.NamingConventions.Test", "EFCore.NamingConventions.Test\EFCore.NamingConventions.Test.csproj", "{AF58C6DC-FF41-4019-B4F3-B8D59A2DAD5F}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F7AE70A6-D237-4257-84F4-A32375E78E10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F7AE70A6-D237-4257-84F4-A32375E78E10}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F7AE70A6-D237-4257-84F4-A32375E78E10}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F7AE70A6-D237-4257-84F4-A32375E78E10}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AF58C6DC-FF41-4019-B4F3-B8D59A2DAD5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF58C6DC-FF41-4019-B4F3-B8D59A2DAD5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AF58C6DC-FF41-4019-B4F3-B8D59A2DAD5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AF58C6DC-FF41-4019-B4F3-B8D59A2DAD5F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
24
EFCore.NamingConventions.sln.DotSettings
Normal file
24
EFCore.NamingConventions.sln.DotSettings
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
|
||||||
|
<!-- Code editing -->
|
||||||
|
<s:String x:Key="/Default/CodeEditing/Localization/Localizable/@EntryValue">No</s:String>
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/ReadSettingsFromFileLevel/@EntryValue">True</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/UsageCheckingInspectionLevel/@EntryValue">InternalsOnly</s:String>
|
||||||
|
|
||||||
|
<!-- Code inspection -->
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/ImplicitNullability/Enabled/@EntryValue">True</s:Boolean>
|
||||||
|
|
||||||
|
<!-- C# formatting -->
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_PRIVATE_MODIFIER/@EntryValue">Implicit</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_CASE_FROM_SWITCH/@EntryValue">False</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Npgsql/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Rewriter/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
||||||
|
</wpf:ResourceDictionary>
|
||||||
BIN
EFCore.NamingConventions.snk
Normal file
BIN
EFCore.NamingConventions.snk
Normal file
Binary file not shown.
110
EFCore.NamingConventions/Check.cs
Normal file
110
EFCore.NamingConventions/Check.cs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace Microsoft.EntityFrameworkCore
|
||||||
|
{
|
||||||
|
[DebuggerStepThrough]
|
||||||
|
internal static class Check
|
||||||
|
{
|
||||||
|
[ContractAnnotation("value:null => halt")]
|
||||||
|
public static T NotNull<T>([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(value, null))
|
||||||
|
{
|
||||||
|
NotEmpty(parameterName, nameof(parameterName));
|
||||||
|
|
||||||
|
throw new ArgumentNullException(parameterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ContractAnnotation("value:null => halt")]
|
||||||
|
public static T NotNull<T>(
|
||||||
|
[NoEnumeration] T value,
|
||||||
|
[InvokerParameterName] [NotNull] string parameterName,
|
||||||
|
[NotNull] string propertyName)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(value, null))
|
||||||
|
{
|
||||||
|
NotEmpty(parameterName, nameof(parameterName));
|
||||||
|
NotEmpty(propertyName, nameof(propertyName));
|
||||||
|
|
||||||
|
throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ContractAnnotation("value:null => halt")]
|
||||||
|
public static IReadOnlyList<T> NotEmpty<T>(IReadOnlyList<T> value, [InvokerParameterName] [NotNull] string parameterName)
|
||||||
|
{
|
||||||
|
NotNull(value, parameterName);
|
||||||
|
|
||||||
|
if (value.Count == 0)
|
||||||
|
{
|
||||||
|
NotEmpty(parameterName, nameof(parameterName));
|
||||||
|
|
||||||
|
throw new ArgumentException(AbstractionsStrings.CollectionArgumentIsEmpty(parameterName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ContractAnnotation("value:null => halt")]
|
||||||
|
public static string NotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName)
|
||||||
|
{
|
||||||
|
Exception e = null;
|
||||||
|
if (ReferenceEquals(value, null))
|
||||||
|
{
|
||||||
|
e = new ArgumentNullException(parameterName);
|
||||||
|
}
|
||||||
|
else if (value.Trim().Length == 0)
|
||||||
|
{
|
||||||
|
e = new ArgumentException(AbstractionsStrings.ArgumentIsEmpty(parameterName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
NotEmpty(parameterName, nameof(parameterName));
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NullButNotEmpty([CanBeNull] string value, [InvokerParameterName] [NotNull] string parameterName)
|
||||||
|
{
|
||||||
|
if (!ReferenceEquals(value, null)
|
||||||
|
&& (value.Length == 0))
|
||||||
|
{
|
||||||
|
NotEmpty(parameterName, nameof(parameterName));
|
||||||
|
|
||||||
|
throw new ArgumentException(AbstractionsStrings.ArgumentIsEmpty(parameterName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IReadOnlyList<T> HasNoNulls<T>(IReadOnlyList<T> value, [InvokerParameterName] [NotNull] string parameterName)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
NotNull(value, parameterName);
|
||||||
|
|
||||||
|
if (value.Any(e => e == null))
|
||||||
|
{
|
||||||
|
NotEmpty(parameterName, nameof(parameterName));
|
||||||
|
|
||||||
|
throw new ArgumentException(parameterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
EFCore.NamingConventions/CodeAnnotations.cs
Normal file
108
EFCore.NamingConventions/CodeAnnotations.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace JetBrains.Annotations
|
||||||
|
{
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Method | AttributeTargets.Parameter |
|
||||||
|
AttributeTargets.Property | AttributeTargets.Delegate |
|
||||||
|
AttributeTargets.Field)]
|
||||||
|
internal sealed class NotNullAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Method | AttributeTargets.Parameter |
|
||||||
|
AttributeTargets.Property | AttributeTargets.Delegate |
|
||||||
|
AttributeTargets.Field)]
|
||||||
|
internal sealed class CanBeNullAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter)]
|
||||||
|
internal sealed class InvokerParameterNameAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter)]
|
||||||
|
internal sealed class NoEnumerationAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
internal sealed class ContractAnnotationAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Contract { get; }
|
||||||
|
|
||||||
|
public bool ForceFullStates { get; }
|
||||||
|
|
||||||
|
public ContractAnnotationAttribute([NotNull] string contract)
|
||||||
|
: this(contract, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates)
|
||||||
|
{
|
||||||
|
Contract = contract;
|
||||||
|
ForceFullStates = forceFullStates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.All)]
|
||||||
|
internal sealed class UsedImplicitlyAttribute : Attribute
|
||||||
|
{
|
||||||
|
public UsedImplicitlyAttribute()
|
||||||
|
: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
|
||||||
|
: this(useKindFlags, ImplicitUseTargetFlags.Default)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
|
||||||
|
: this(ImplicitUseKindFlags.Default, targetFlags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public UsedImplicitlyAttribute(
|
||||||
|
ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
|
||||||
|
{
|
||||||
|
UseKindFlags = useKindFlags;
|
||||||
|
TargetFlags = targetFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImplicitUseKindFlags UseKindFlags { get; }
|
||||||
|
public ImplicitUseTargetFlags TargetFlags { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate)]
|
||||||
|
internal sealed class StringFormatMethodAttribute : Attribute
|
||||||
|
{
|
||||||
|
public StringFormatMethodAttribute([NotNull] string formatParameterName)
|
||||||
|
=> FormatParameterName = formatParameterName;
|
||||||
|
|
||||||
|
[NotNull]
|
||||||
|
public string FormatParameterName { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum ImplicitUseKindFlags
|
||||||
|
{
|
||||||
|
Default = Access | Assign | InstantiatedWithFixedConstructorSignature,
|
||||||
|
Access = 1,
|
||||||
|
Assign = 2,
|
||||||
|
InstantiatedWithFixedConstructorSignature = 4,
|
||||||
|
InstantiatedNoFixedConstructorSignature = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum ImplicitUseTargetFlags
|
||||||
|
{
|
||||||
|
Default = Itself,
|
||||||
|
Itself = 1,
|
||||||
|
Members = 2,
|
||||||
|
WithMembers = Itself | Members
|
||||||
|
}
|
||||||
|
}
|
||||||
27
EFCore.NamingConventions/EFCore.NamingConventions.csproj
Normal file
27
EFCore.NamingConventions/EFCore.NamingConventions.csproj
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyName>EFCore.NamingConventions</AssemblyName>
|
||||||
|
<RootNamespace>EFCore</RootNamespace>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
<VersionPrefix>1.0.0</VersionPrefix>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
|
<AssemblyOriginatorKeyFile>../EFCore.NamingConventions.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<Description>Naming Conventions for Entity Framework Core Tables and Columns.</Description>
|
||||||
|
<Authors>Shay Rojansky</Authors>
|
||||||
|
<Copyright>Copyright 2019 © Shay Rojansky</Copyright>
|
||||||
|
<PackageTags>Entity Framework Core;entity-framework-core;ef;efcore;orm;sql;postgresql;npgsql</PackageTags>
|
||||||
|
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<RepositoryUrl>git://github.com/efcore/EFCore.NamingConventions</RepositoryUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="$(EFCoreVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="$(EFCoreVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace EFCore.NamingConventions.Internal
|
||||||
|
{
|
||||||
|
enum NamingConvention
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
SnakeCase
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace EFCore.NamingConventions.Internal
|
||||||
|
{
|
||||||
|
public class NamingConventionSetPlugin : IConventionSetPlugin
|
||||||
|
{
|
||||||
|
readonly IDbContextOptions _options;
|
||||||
|
|
||||||
|
public NamingConventionSetPlugin([NotNull] IDbContextOptions options) => _options = options;
|
||||||
|
|
||||||
|
public ConventionSet ModifyConventions(ConventionSet conventionSet)
|
||||||
|
{
|
||||||
|
var namingStyle = _options.FindExtension<NamingConventionsOptionsExtension>().NamingConvention;
|
||||||
|
|
||||||
|
if (namingStyle == NamingConvention.None)
|
||||||
|
return conventionSet;
|
||||||
|
|
||||||
|
var nameRewriter = namingStyle switch
|
||||||
|
{
|
||||||
|
NamingConvention.SnakeCase => new SnakeCaseNameRewriter(),
|
||||||
|
_ => throw new NotImplementedException("Unhandled enum value: " + namingStyle)
|
||||||
|
};
|
||||||
|
|
||||||
|
conventionSet.EntityTypeAddedConventions.Add(nameRewriter);
|
||||||
|
conventionSet.PropertyAddedConventions.Add(nameRewriter);
|
||||||
|
return conventionSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace EFCore.NamingConventions.Internal
|
||||||
|
{
|
||||||
|
public class NamingConventionsOptionsExtension : IDbContextOptionsExtension
|
||||||
|
{
|
||||||
|
DbContextOptionsExtensionInfo _info;
|
||||||
|
NamingConvention _namingConvention;
|
||||||
|
|
||||||
|
public NamingConventionsOptionsExtension() {}
|
||||||
|
|
||||||
|
protected NamingConventionsOptionsExtension([NotNull] NamingConventionsOptionsExtension copyFrom)
|
||||||
|
=> _namingConvention = copyFrom._namingConvention;
|
||||||
|
|
||||||
|
public virtual DbContextOptionsExtensionInfo Info => _info ??= new ExtensionInfo(this);
|
||||||
|
|
||||||
|
protected virtual NamingConventionsOptionsExtension Clone() => new NamingConventionsOptionsExtension(this);
|
||||||
|
|
||||||
|
internal virtual NamingConvention NamingConvention => _namingConvention;
|
||||||
|
|
||||||
|
public virtual NamingConventionsOptionsExtension WithoutNaming()
|
||||||
|
{
|
||||||
|
var clone = Clone();
|
||||||
|
clone._namingConvention = NamingConvention.None;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual NamingConventionsOptionsExtension WithSnakeCaseNaming()
|
||||||
|
{
|
||||||
|
var clone = Clone();
|
||||||
|
clone._namingConvention = NamingConvention.SnakeCase;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Validate(IDbContextOptions options) {}
|
||||||
|
|
||||||
|
public void ApplyServices(IServiceCollection services)
|
||||||
|
=> services.AddEntityFrameworkNamingConventions();
|
||||||
|
|
||||||
|
sealed class ExtensionInfo : DbContextOptionsExtensionInfo
|
||||||
|
{
|
||||||
|
string _logFragment;
|
||||||
|
|
||||||
|
public ExtensionInfo(IDbContextOptionsExtension extension) : base(extension) {}
|
||||||
|
|
||||||
|
new NamingConventionsOptionsExtension Extension
|
||||||
|
=> (NamingConventionsOptionsExtension)base.Extension;
|
||||||
|
|
||||||
|
public override bool IsDatabaseProvider => false;
|
||||||
|
|
||||||
|
public override string LogFragment
|
||||||
|
=> _logFragment ??= Extension._namingConvention switch
|
||||||
|
{
|
||||||
|
NamingConvention.SnakeCase => "using snake-case naming ",
|
||||||
|
_ => ""
|
||||||
|
};
|
||||||
|
|
||||||
|
public override long GetServiceProviderHashCode() => Extension._namingConvention.GetHashCode();
|
||||||
|
|
||||||
|
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
|
||||||
|
=> debugInfo["Naming:" + nameof(NamingConventionsExtensions.UseSnakeCaseNamingConventions)]
|
||||||
|
= Extension._namingConvention.GetHashCode().ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
|
||||||
|
|
||||||
|
namespace EFCore.NamingConventions.Internal
|
||||||
|
{
|
||||||
|
class SnakeCaseNameRewriter : IEntityTypeAddedConvention, IPropertyAddedConvention
|
||||||
|
{
|
||||||
|
public void ProcessEntityTypeAdded(
|
||||||
|
IConventionEntityTypeBuilder entityTypeBuilder,
|
||||||
|
IConventionContext<IConventionEntityTypeBuilder> context)
|
||||||
|
=> entityTypeBuilder.ToTable(
|
||||||
|
ConvertToSnakeCase(entityTypeBuilder.Metadata.GetTableName()),
|
||||||
|
entityTypeBuilder.Metadata.GetSchema());
|
||||||
|
|
||||||
|
public void ProcessPropertyAdded(
|
||||||
|
IConventionPropertyBuilder propertyBuilder,
|
||||||
|
IConventionContext<IConventionPropertyBuilder> context)
|
||||||
|
=> propertyBuilder.HasColumnName(
|
||||||
|
ConvertToSnakeCase(propertyBuilder.Metadata.GetColumnName()));
|
||||||
|
|
||||||
|
static string ConvertToSnakeCase(string value)
|
||||||
|
{
|
||||||
|
const char underscore = '_';
|
||||||
|
const UnicodeCategory noneCategory = UnicodeCategory.Control;
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
var previousCategory = noneCategory;
|
||||||
|
|
||||||
|
for (var currentIndex = 0; currentIndex < value.Length; currentIndex++)
|
||||||
|
{
|
||||||
|
var currentChar = value[currentIndex];
|
||||||
|
if (currentChar == underscore)
|
||||||
|
{
|
||||||
|
builder.Append(underscore);
|
||||||
|
previousCategory = noneCategory;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentCategory = char.GetUnicodeCategory(currentChar);
|
||||||
|
switch (currentCategory)
|
||||||
|
{
|
||||||
|
case UnicodeCategory.UppercaseLetter:
|
||||||
|
case UnicodeCategory.TitlecaseLetter:
|
||||||
|
if (previousCategory == UnicodeCategory.SpaceSeparator ||
|
||||||
|
previousCategory == UnicodeCategory.LowercaseLetter ||
|
||||||
|
previousCategory != UnicodeCategory.DecimalDigitNumber &&
|
||||||
|
currentIndex > 0 &&
|
||||||
|
currentIndex + 1 < value.Length &&
|
||||||
|
char.IsLower(value[currentIndex + 1]))
|
||||||
|
{
|
||||||
|
builder.Append(underscore);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentChar = char.ToLower(currentChar);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UnicodeCategory.LowercaseLetter:
|
||||||
|
case UnicodeCategory.DecimalDigitNumber:
|
||||||
|
if (previousCategory == UnicodeCategory.SpaceSeparator)
|
||||||
|
builder.Append(underscore);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (previousCategory != noneCategory)
|
||||||
|
previousCategory = UnicodeCategory.SpaceSeparator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(currentChar);
|
||||||
|
previousCategory = currentCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
EFCore.NamingConventions/NamingConventionsExtensions.cs
Normal file
26
EFCore.NamingConventions/NamingConventionsExtensions.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using EFCore.NamingConventions.Internal;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace Microsoft.EntityFrameworkCore
|
||||||
|
{
|
||||||
|
public static class NamingConventionsExtensions
|
||||||
|
{
|
||||||
|
public static DbContextOptionsBuilder UseSnakeCaseNamingConventions([NotNull] this DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
Check.NotNull(optionsBuilder, nameof(optionsBuilder));
|
||||||
|
|
||||||
|
var extension = (optionsBuilder.Options.FindExtension<NamingConventionsOptionsExtension>() ?? new NamingConventionsOptionsExtension())
|
||||||
|
.WithSnakeCaseNaming();
|
||||||
|
|
||||||
|
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
|
||||||
|
|
||||||
|
return optionsBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DbContextOptionsBuilder<TContext> UseSnakeCaseNamingConventions<TContext>([NotNull] this DbContextOptionsBuilder<TContext> optionsBuilder)
|
||||||
|
where TContext : DbContext
|
||||||
|
=> (DbContextOptionsBuilder<TContext>)UseSnakeCaseNamingConventions((DbContextOptionsBuilder)optionsBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
|
||||||
|
using EFCore.NamingConventions.Internal;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="Microsoft.Extensions.DependencyInjection.IServiceCollection" />.
|
||||||
|
/// </summary>
|
||||||
|
public static class NamingConventionsServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para>
|
||||||
|
/// Adds the services required for proxy support in Entity Framework. You use this method when
|
||||||
|
/// using dependency injection in your application, such as with ASP.NET. For more information
|
||||||
|
/// on setting up dependency injection, see http://go.microsoft.com/fwlink/?LinkId=526890.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// You only need to use this functionality when you want Entity Framework to resolve the services it uses
|
||||||
|
/// from an external dependency injection container. If you are not using an external
|
||||||
|
/// dependency injection container, Entity Framework will take care of creating the services it requires.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceCollection">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The same service collection so that multiple calls can be chained.
|
||||||
|
/// </returns>
|
||||||
|
public static IServiceCollection AddEntityFrameworkNamingConventions(
|
||||||
|
[NotNull] this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
Check.NotNull(serviceCollection, nameof(serviceCollection));
|
||||||
|
|
||||||
|
new EntityFrameworkServicesBuilder(serviceCollection)
|
||||||
|
.TryAdd<IConventionSetPlugin, NamingConventionSetPlugin>();
|
||||||
|
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
201
LICENSE.txt
Normal file
201
LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
47
README.md
Normal file
47
README.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Naming Conventions for Entity Framework Core Tables and Columns
|
||||||
|
|
||||||
|
By default, EF Core will map to tables and columns named exactly after your .NET classes and properties. For example, mapping a typical Customer class to PostgreSQL will result in SQL such as the following:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE "Customers" (
|
||||||
|
"Id" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
"FullName" text NULL,
|
||||||
|
CONSTRAINT "PK_Customers" PRIMARY KEY ("Id")
|
||||||
|
);
|
||||||
|
|
||||||
|
SELECT c."Id", c."FullName"
|
||||||
|
FROM "Customers" AS c
|
||||||
|
WHERE c."FullName" = 'John Doe';
|
||||||
|
```
|
||||||
|
|
||||||
|
For PostgreSQL specifically, this forces double-quotes to be added since unquoted identifiers are automatically converted to lower-case - and all those quotes are an eye-sore. But even if we're using another database such as SQL Server, maybe we just hate seeing upper-case letters in our database, and would rather have another naming convention.
|
||||||
|
|
||||||
|
Down with same-name identifier tyranny! Simply add a reference to [EFCore.NamingConventions](https://www.nuget.org/packages/EFCore.NamingConventions/1.0.0-rc1) and enable a naming convention in your model's `OnConfiguring` method:
|
||||||
|
|
||||||
|
```c#
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
=> optionsBuilder
|
||||||
|
.UseNpgsql(...)
|
||||||
|
.UseSnakeCaseNamingConventions();
|
||||||
|
```
|
||||||
|
|
||||||
|
This will automatically make all your table and column names have snake_case naming:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE customers (
|
||||||
|
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
full_name text NULL,
|
||||||
|
CONSTRAINT "PK_customers" PRIMARY KEY (id);
|
||||||
|
|
||||||
|
SELECT c.id, c.full_name
|
||||||
|
FROM customers AS c
|
||||||
|
WHERE c.full_name = 'John Doe';
|
||||||
|
```
|
||||||
|
|
||||||
|
Currently, only snake_case is supported, but we can add more conventions as people request them.
|
||||||
|
|
||||||
|
Some important notes:
|
||||||
|
|
||||||
|
* If you have an existing database, adding this naming convention will cause a migration to produced, renaming everything. Be very cautious when doing this (the process currently involves dropping and recreating primary keys).
|
||||||
|
* This plugin will work with any database provider and isn't related to PostgreSQL or Npgsql in any way.
|
||||||
|
* This is a community-maintained plugin: it isn't an official part of Entity Framework Core and isn't supported by Microsoft in any way.
|
||||||
5
global.json
Normal file
5
global.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"sdk": {
|
||||||
|
"version": "3.0.100-preview9-014004"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user