├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── publish-nuget.yml
├── .gitignore
├── Directory.Build.props
├── Directory.Build.targets
├── LICENSE
├── README.md
├── SpatialFocus.EntityFrameworkCore.Extensions.ruleset
├── SpatialFocus.EntityFrameworkCore.Extensions.sln
├── SpatialFocus.EntityFrameworkCore.Extensions.sln.DotSettings
├── docs
└── nuget-icon.png
├── samples
└── SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo
│ ├── Data
│ └── DemoContext.cs
│ ├── Entities
│ ├── Product.cs
│ ├── ProductCategory.cs
│ ├── Review.cs
│ ├── ReviewRating.cs
│ └── SpecialOccasion.cs
│ ├── Program.cs
│ └── SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.csproj
├── src
└── SpatialFocus.EntityFrameworkCore.Extensions
│ ├── EnumLookupAttribute.cs
│ ├── EnumLookupExtension.cs
│ ├── EnumLookupOptions.cs
│ ├── EnumWithNumberLookup.cs
│ ├── EnumWithNumberLookupAndDescription.cs
│ ├── EnumWithStringLookup.cs
│ ├── EnumWithStringLookupAndDescription.cs
│ ├── NamingExtension.cs
│ ├── NamingOptions.cs
│ ├── NamingScheme.cs
│ ├── NamingSource.cs
│ └── SpatialFocus.EntityFrameworkCore.Extensions.csproj
├── stylecop.json
└── test
└── SpatialFocus.EntityFrameworkCore.Extensions.Test
├── Entities
├── Product.cs
├── ProductCategory.cs
├── ProductTag.cs
└── SpecialOccasion.cs
├── NamingOptionsTest.cs
├── ProductContext.cs
└── SpatialFocus.EntityFrameworkCore.Extensions.Test.csproj
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Modified version of https://github.com/dotnet/roslyn/blob/d0ca6f34aff907a9cafde9f629397cc153bb94fe/.editorconfig
2 | # Rules documentation https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
3 |
4 | # top-most EditorConfig file
5 | root = true
6 |
7 | # Don't use tabs for indentation.
8 | [*]
9 | indent_style = tab
10 | trim_trailing_whitespace = true
11 | insert_final_newline = false
12 | # (Please don't specify an indent_size here; that has too many unintended consequences.)
13 |
14 | # Code files
15 | [*.{cs,csx,vb,vbx}]
16 | indent_size = 4
17 |
18 | # Xml project files
19 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
20 | indent_size = 2
21 |
22 | # Xml config files
23 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
24 | indent_size = 2
25 |
26 | # JSON files
27 | [*.json]
28 | indent_size = 2
29 |
30 | # JS and TS files
31 | [*.{js,ts}]
32 | indent_size = 2
33 |
34 | # Dotnet code style settings:
35 | [*.{cs,vb}]
36 | # Sort using and Import directives with System.* appearing first
37 | dotnet_sort_system_directives_first = true
38 | # Avoid "this." and "Me." if not necessary
39 | dotnet_style_qualification_for_field = true:suggestion
40 | dotnet_style_qualification_for_property = false:suggestion
41 | dotnet_style_qualification_for_method = false:suggestion
42 | dotnet_style_qualification_for_event = false:suggestion
43 |
44 | # Use language keywords instead of framework type names for type references
45 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
46 | dotnet_style_predefined_type_for_member_access = true:suggestion
47 |
48 | # Suggest more modern language features when available
49 | dotnet_style_object_initializer = true:suggestion
50 | dotnet_style_collection_initializer = true:suggestion
51 | dotnet_style_coalesce_expression = true:suggestion
52 | dotnet_style_null_propagation = true:suggestion
53 | dotnet_style_explicit_tuple_names = true:suggestion
54 |
55 | # CSharp code style settings:
56 | [*.cs]
57 | # Prefer "var" everywhere
58 | csharp_style_var_for_built_in_types = false:suggestion
59 | csharp_style_var_when_type_is_apparent = false:suggestion
60 | csharp_style_var_elsewhere = false:suggestion
61 |
62 | # Prefer method-like constructs to have a block body
63 | csharp_style_expression_bodied_methods = false:suggestion
64 | csharp_style_expression_bodied_constructors = false:suggestion
65 | csharp_style_expression_bodied_operators = false:suggestion
66 |
67 | # Prefer property-like constructs to have an expression-body
68 | csharp_style_expression_bodied_properties = true:suggestion
69 | csharp_style_expression_bodied_indexers = true:suggestion
70 | csharp_style_expression_bodied_accessors = true:suggestion
71 |
72 | # Suggest more modern language features when available
73 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
74 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
75 | csharp_style_inlined_variable_declaration = true:suggestion
76 | csharp_style_throw_expression = true:suggestion
77 | csharp_style_conditional_delegate_call = true:suggestion
78 |
79 | # Newline settings
80 | csharp_new_line_before_open_brace = all
81 | csharp_new_line_before_else = true
82 | csharp_new_line_before_catch = true
83 | csharp_new_line_before_finally = true
84 | csharp_new_line_before_members_in_object_initializers = true
85 | csharp_new_line_before_members_in_anonymous_types = true
86 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/publish-nuget.yml:
--------------------------------------------------------------------------------
1 | name: Build and publish NuGet
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | publish:
11 | name: build, pack & publish
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: actions/setup-dotnet@v1
16 | with:
17 | dotnet-version: |
18 | 3.1.x
19 | 5.0.x
20 | 6.0.x
21 | 8.0.x
22 | - name: Build
23 | run: dotnet build --configuration Release
24 | - name: Pack
25 | run: dotnet pack src/SpatialFocus.EntityFrameworkCore.Extensions/SpatialFocus.EntityFrameworkCore.Extensions.csproj --output . --configuration Release
26 | - name: Push
27 | run: dotnet nuget push *.nupkg --skip-duplicate --api-key ${{secrets.nuget_api_key}} --source https://api.nuget.org/v3/index.json
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Visual Studio (>=2015) project-specific, machine local files
5 | .vs/
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.sln.docstates
11 | *.userprefs
12 |
13 | # ignore Xamarin.Android Resource.Designer.cs files
14 | **/*.Droid/**/[Rr]esource.[Dd]esigner.cs
15 | **/*.Android/**/[Rr]esource.[Dd]esigner.cs
16 | **/Android/**/[Rr]esource.[Dd]esigner.cs
17 | **/Droid/**/[Rr]esource.[Dd]esigner.cs
18 |
19 | # Xamarin Components
20 | Components/
21 |
22 | # Build results
23 | [Dd]ebug/
24 | [Dd]ebugPublic/
25 | [Rr]elease/
26 | x64/
27 | build/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | #NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | *_i.c
46 | *_p.c
47 | *_i.h
48 | *.ilk
49 | *.meta
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding addin-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | *.ncrunch*
108 | _NCrunch_*
109 | .*crunch*.local.xml
110 |
111 | # MightyMoose
112 | *.mm.*
113 | AutoTest.Net/
114 |
115 | # Web workbench (sass)
116 | .sass-cache/
117 |
118 | # Installshield output folder
119 | [Ee]xpress/
120 |
121 | # DocProject is a documentation generator add-in
122 | DocProject/buildhelp/
123 | DocProject/Help/*.HxT
124 | DocProject/Help/*.HxC
125 | DocProject/Help/*.hhc
126 | DocProject/Help/*.hhk
127 | DocProject/Help/*.hhp
128 | DocProject/Help/Html2
129 | DocProject/Help/html
130 |
131 | # Click-Once directory
132 | publish/
133 |
134 | # Publish Web Output
135 | *.[Pp]ublish.xml
136 | *.azurePubxml
137 |
138 | # NuGet Packages Directory
139 | .nuget/
140 | packages/
141 | *.nuget.targets
142 | *.lock.json
143 | *.nuget.props
144 |
145 | ## TODO: If the tool you use requires repositories.config uncomment the next line
146 | #!packages/repositories.config
147 |
148 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
149 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented)
150 | !packages/build/
151 |
152 | # Windows Azure Build Output
153 | csx/
154 | *.build.csdef
155 |
156 | # Windows Store app package directory
157 | AppPackages/
158 |
159 | # Others
160 | sql/
161 | *.Cache
162 | ClientBin/
163 | [Ss]tyle[Cc]op.*
164 | ~$*
165 | *~
166 | *.dbmdl
167 | *.dbproj.schemaview
168 | *.pfx
169 | *.publishsettings
170 | node_modules/
171 | .DS_Store
172 | *.bak
173 |
174 | # RIA/Silverlight projects
175 | Generated_Code/
176 |
177 | # Backup & report files from converting an old project file to a newer
178 | # Visual Studio version. Backup files are not needed, because we have git ;-)
179 | _UpgradeReport_Files/
180 | Backup*/
181 | UpgradeLog*.XML
182 | UpgradeLog*.htm
183 |
184 | # SQL Server files
185 | *.mdf
186 | *.ldf
187 |
188 | # Business Intelligence projects
189 | *.rdl.data
190 | *.bim.layout
191 | *.bim_*.settings
192 |
193 | # Microsoft Fakes
194 | FakesAssemblies/
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(MSBuildThisFileDirectory)SpatialFocus.EntityFrameworkCore.Extensions.ruleset
4 |
5 |
6 |
7 | 1.2.0-beta.113
8 | all
9 |
10 |
11 | stylecop.json
12 |
13 |
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Spatial Focus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SpatialFocus.EntityFrameworkCore.Extensions
2 |
3 | A set of useful extensions for EntityFrameworkCore (Enum Lookup Tables, Naming of tables / properties / keys, Pluralize).
4 |
5 | [](https://github.com/SpatialFocus/EntityFrameworkCore.Extensions/actions/workflows/publish-nuget.yml)
6 | [](https://www.nuget.org/packages/SpatialFocus.EntityFrameworkCore.Extensions/)
7 | [](https://app.fossa.com/projects/git%2Bgithub.com%2FSpatialFocus%2FEntityFrameworkCore.Extensions?ref=badge_shield)
8 |
9 | ## Installation
10 |
11 | ```console
12 | Install-Package SpatialFocus.EntityFrameworkCore.Extensions
13 | ```
14 |
15 | ## Usage
16 |
17 | This extension provides two extension methods to modify the `modelBuilder` in the `OnModelCreating` method in the `DbContext` class.
18 |
19 | ```csharp
20 | using SpatialFocus.EntityFrameworkCore.Extensions;
21 |
22 | public partial class MyContext : DbContext
23 | {
24 | // ...
25 |
26 | protected override void OnModelCreating(ModelBuilder modelBuilder)
27 | {
28 | // Any custom model configuration should come before calling ConfigureEnumLookup and ConfigureNames
29 | // ...
30 |
31 | modelBuilder.ConfigureEnumLookup(EnumLookupOptions.Default.UseStringAsIdentifier());
32 |
33 | modelBuilder.ConfigureNames(NamingOptions.Default.SkipTableNamingForGenericEntityTypes());
34 |
35 | // Any configuration after calling the two methods will not be processed by this Extension
36 | // ...
37 | }
38 | }
39 | ```
40 |
41 | ## Configuration Options
42 |
43 | There are two extension methods in the `OnModelCreating` method in the `DbContext` class:
44 |
45 | - **ConfigureEnumLookup(...)** allows you to define in which form lookup tables for *Enums* will be constructed and named:
46 |
47 | - **Default** defines the naming scheme for the table to use *snake_case* and to use the number lookup format.
48 | - **UseNumberAsIdentifier()** or **UseStringAsIdentifier()** defines whether the lookup table will be based on the string enum values or the numeric enum value as primary key in the resulting table and as foreign key in the relation.
49 | - **Singularize()** or **Pluralize()** defines whether the table names will be the singular or plural versions of the enum type.
50 | - **SetNamingScheme(...)** allows you to override the naming using one of the predefined schemes (see below) or a custom function.
51 | - **UseEnumsWithAttributeOnly()** to generate the enum lookup tables only for enums marked with the `[EnumLookup]` attribute
52 | - **SetDeleteBehavior(...)** to configure the delete behavior for the generated FKs, using the `Microsoft.EntityFrameworkCore.DeleteBehavior` enum (defaults to _Cascade_)
53 | - **Please note:** For owned entities, you should call the **ConfigureOwnedEnumLookup(...)** method on the `OwnedNavigationBuilder`. Please see [#16](/../../issues/16) for more details. E.g. `modelBuilder.Entity().OwnsOne(x => x.Address, ownedBuilder => ownedBuilder.ConfigureOwnedEnumLookup(...));`
54 |
55 | - **ConfigureNames(...)** allows you to define in which form tables, properties and constraints will be named:
56 |
57 | - **Default** defines the naming scheme for the elemens to use *snake_case* for naming and the *DbSet name* to name the tables.
58 | - **SetTableNamingSource(...)** defines which naming source to use (see below). It means whether to use the ClrType name or the DbSet name to name the tables.
59 | - **Singularize()** or **Pluralize()** defines whether the table names will be the singular or plural versions.
60 | - **SetNamingScheme(...)** allows you to override the naming using one of the predefined schemes (see below) or a custom function.
61 | - **OverrideTableNaming(...)**, **OverrideColumnNaming(...)**, **OverrideConstraintNaming(...)** to deviate from the general naming scheme.
62 | - **SkipEntireEntities(...)** and **SkipTableNamingForEntities(...)** to skip the naming for either the whole entity or just the table name for certain entities by using a `Func` skip function, e.g. `SkipEntireEntities(entity => entity.Name == "MyEntity")`.
63 | - **SkipTableNamingForGenericEntityTypes()** should be used to avoid naming the Enum lookup tables which can lead to unwanted results.
64 |
65 | ### Naming Schemes
66 |
67 | - NamingScheme.SnakeCase
68 | - NamingScheme.ScreamingSnakeCase
69 | - NamingScheme.KebabCase
70 | - Any custom `Func`, e.g. `SetNamingScheme(name => name.ToLower())`
71 |
72 | #### Naming Source
73 |
74 | - NamingSource.ClrType
75 | - NamingSource.DbSet
76 |
77 | ## Examples
78 |
79 | For an exemplary usage, see the `DemoContext` in the [sample project](https://github.com/SpatialFocus/SpatialFocus.EntityFrameworkCore.Extensions/tree/master/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo).
80 |
81 | ## License
82 |
83 | [](https://app.fossa.com/projects/git%2Bgithub.com%2FSpatialFocus%2FEntityFrameworkCore.Extensions?ref=badge_large)
84 |
85 | ----
86 |
87 | Made with :heart: by [Spatial Focus](https://spatial-focus.net/)
88 |
--------------------------------------------------------------------------------
/SpatialFocus.EntityFrameworkCore.Extensions.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/SpatialFocus.EntityFrameworkCore.Extensions.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29709.97
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpatialFocus.EntityFrameworkCore.Extensions", "src\SpatialFocus.EntityFrameworkCore.Extensions\SpatialFocus.EntityFrameworkCore.Extensions.csproj", "{768CB889-C6A3-475B-B8EE-72CE676DD5B8}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo", "samples\SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo\SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.csproj", "{28AC20A6-FE86-427F-80D9-19D5D02D31FB}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{70FF5B08-F25B-44BE-B8FE-1F1884B5B3F0}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{8092090A-24E1-45E6-84B3-AA060CC34619}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2C1E7909-3D0A-462C-AEE1-21D583FBCFD2}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "global", "global", "{AA695DE3-C613-4023-97F5-BF3841C5E233}"
17 | ProjectSection(SolutionItems) = preProject
18 | .editorconfig = .editorconfig
19 | .gitattributes = .gitattributes
20 | .gitignore = .gitignore
21 | Directory.Build.props = Directory.Build.props
22 | Directory.Build.targets = Directory.Build.targets
23 | LICENSE = LICENSE
24 | README.md = README.md
25 | SpatialFocus.EntityFrameworkCore.Extensions.ruleset = SpatialFocus.EntityFrameworkCore.Extensions.ruleset
26 | SpatialFocus.EntityFrameworkCore.Extensions.sln.DotSettings = SpatialFocus.EntityFrameworkCore.Extensions.sln.DotSettings
27 | stylecop.json = stylecop.json
28 | EndProjectSection
29 | EndProject
30 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpatialFocus.EntityFrameworkCore.Extensions.Test", "test\SpatialFocus.EntityFrameworkCore.Extensions.Test\SpatialFocus.EntityFrameworkCore.Extensions.Test.csproj", "{F40647CD-65D8-4FD0-8391-88F7CD8D976D}"
31 | EndProject
32 | Global
33 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
34 | Debug|Any CPU = Debug|Any CPU
35 | Release|Any CPU = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
38 | {768CB889-C6A3-475B-B8EE-72CE676DD5B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {768CB889-C6A3-475B-B8EE-72CE676DD5B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {768CB889-C6A3-475B-B8EE-72CE676DD5B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {768CB889-C6A3-475B-B8EE-72CE676DD5B8}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {28AC20A6-FE86-427F-80D9-19D5D02D31FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {28AC20A6-FE86-427F-80D9-19D5D02D31FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {28AC20A6-FE86-427F-80D9-19D5D02D31FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {28AC20A6-FE86-427F-80D9-19D5D02D31FB}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {F40647CD-65D8-4FD0-8391-88F7CD8D976D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {F40647CD-65D8-4FD0-8391-88F7CD8D976D}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {F40647CD-65D8-4FD0-8391-88F7CD8D976D}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {F40647CD-65D8-4FD0-8391-88F7CD8D976D}.Release|Any CPU.Build.0 = Release|Any CPU
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | GlobalSection(NestedProjects) = preSolution
55 | {768CB889-C6A3-475B-B8EE-72CE676DD5B8} = {70FF5B08-F25B-44BE-B8FE-1F1884B5B3F0}
56 | {28AC20A6-FE86-427F-80D9-19D5D02D31FB} = {8092090A-24E1-45E6-84B3-AA060CC34619}
57 | {F40647CD-65D8-4FD0-8391-88F7CD8D976D} = {2C1E7909-3D0A-462C-AEE1-21D583FBCFD2}
58 | EndGlobalSection
59 | GlobalSection(ExtensibilityGlobals) = postSolution
60 | SolutionGuid = {8D07B300-5F54-4D11-BA2E-668BF1671D72}
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/SpatialFocus.EntityFrameworkCore.Extensions.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | DO_NOT_SHOW
3 | ECMAScript 2016
4 | <?xml version="1.0" encoding="utf-16"?><Profile name="Default"><CSReorderTypeMembers>True</CSReorderTypeMembers><CSUpdateFileHeader>True</CSUpdateFileHeader><CSUseAutoProperty>True</CSUseAutoProperty><CSArrangeQualifiers>True</CSArrangeQualifiers><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="False" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="False" ArrangeVarStyle="True" /><CSEnforceVarKeywordUsageSettings>True</CSEnforceVarKeywordUsageSettings><XMLReformatCode>True</XMLReformatCode></Profile>
5 | Default
6 | USE_TABS_ONLY
7 | USE_TABS_ONLY
8 | 1
9 | 1
10 | 1
11 | 1
12 | 1
13 | 1
14 | 1
15 | False
16 | False
17 | False
18 | NEVER
19 | NEVER
20 | False
21 | NEVER
22 | NEVER
23 | LINE_BREAK
24 | True
25 | False
26 | False
27 | False
28 | True
29 | False
30 | True
31 | False
32 | False
33 | 1
34 | 1
35 | Required
36 | Required
37 | Required
38 | Required
39 | CHOP_IF_LONG
40 | 140
41 | USE_TABS_ONLY
42 | USE_TABS_ONLY
43 | True
44 | True
45 | True
46 | OneStep
47 | html,thead,tbody,tfoot
48 | True
49 | USE_TABS_ONLY
50 | USE_TABS_ONLY
51 | USE_TABS_ONLY
52 | USE_TABS_ONLY
53 | USE_TABS_ONLY
54 | USE_TABS_ONLY
55 | True
56 | OnSingleLine
57 | OneStep
58 | OnSingleLine
59 | OneStep
60 | 1
61 | <copyright file="${File.FileName}" company="Spatial Focus">
62 | Copyright (c) Spatial Focus. All rights reserved.
63 | Licensed under the MIT license. See LICENSE file in the project root for full license information.
64 | </copyright>
65 | UI
66 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
67 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
68 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
69 | <?xml version="1.0" encoding="utf-16"?>
70 | <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
71 | <TypePattern DisplayName="COM interfaces or structs">
72 | <TypePattern.Match>
73 | <Or>
74 | <And>
75 | <Kind Is="Interface" />
76 | <Or>
77 | <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
78 | <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
79 | </Or>
80 | </And>
81 | <Kind Is="Struct" />
82 | </Or>
83 | </TypePattern.Match>
84 | </TypePattern>
85 | <TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All">
86 | <TypePattern.Match>
87 | <And>
88 | <Kind Is="Class" />
89 | <HasMember>
90 | <And>
91 | <Kind Is="Method" />
92 | <HasAttribute Name="Xunit.FactAttribute" Inherited="True" />
93 | </And>
94 | </HasMember>
95 | </And>
96 | </TypePattern.Match>
97 | <Entry DisplayName="Setup/Teardown Methods">
98 | <Entry.Match>
99 | <Or>
100 | <Kind Is="Constructor" />
101 | <And>
102 | <Kind Is="Method" />
103 | <ImplementsInterface Name="System.IDisposable" />
104 | </And>
105 | </Or>
106 | </Entry.Match>
107 | <Entry.SortBy>
108 | <Kind Order="Constructor" />
109 | </Entry.SortBy>
110 | </Entry>
111 | <Entry DisplayName="All other members" />
112 | <Entry Priority="100" DisplayName="Test Methods">
113 | <Entry.Match>
114 | <And>
115 | <Kind Is="Method" />
116 | <HasAttribute Name="Xunit.FactAttribute" />
117 | </And>
118 | </Entry.Match>
119 | <Entry.SortBy>
120 | <Name />
121 | </Entry.SortBy>
122 | </Entry>
123 | </TypePattern>
124 | <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
125 | <TypePattern.Match>
126 | <And>
127 | <Kind Is="Class" />
128 | <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
129 | </And>
130 | </TypePattern.Match>
131 | <Entry DisplayName="Setup/Teardown Methods">
132 | <Entry.Match>
133 | <And>
134 | <Kind Is="Method" />
135 | <Or>
136 | <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
137 | <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
138 | <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
139 | <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
140 | </Or>
141 | </And>
142 | </Entry.Match>
143 | </Entry>
144 | <Entry DisplayName="All other members" />
145 | <Entry Priority="100" DisplayName="Test Methods">
146 | <Entry.Match>
147 | <And>
148 | <Kind Is="Method" />
149 | <HasAttribute Name="NUnit.Framework.TestAttribute" />
150 | </And>
151 | </Entry.Match>
152 | <Entry.SortBy>
153 | <Name />
154 | </Entry.SortBy>
155 | </Entry>
156 | </TypePattern>
157 | <TypePattern DisplayName="Default Pattern">
158 | <Entry DisplayName="All Members">
159 | <Entry.SortBy>
160 | <Kind Order="Constant Field Constructor Destructor Delegate Event Enum Interface Property Indexer Operator Method Struct Class" />
161 | <Access Order="Public Protected Internal Private" />
162 | <Static />
163 | <Readonly />
164 | <Name />
165 | </Entry.SortBy>
166 | </Entry>
167 | </TypePattern>
168 | </Patterns>
169 | UseExplicitType
170 | UseExplicitType
171 | UseExplicitType
172 | True
173 | True
174 | False
175 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
176 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
177 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
178 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
179 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
180 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
181 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
182 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
183 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
184 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
185 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
186 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
187 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
188 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
189 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
190 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
191 | <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" />
192 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
193 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
194 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
195 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
196 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
197 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
198 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
199 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
200 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
201 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
202 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
203 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
204 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
205 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
206 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
207 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
208 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
209 | <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" />
210 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
211 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
212 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
213 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
214 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
215 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
216 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
217 | C:\Users\chris\AppData\Local\JetBrains\Transient\ReSharperPlatformVs15\v11_47ebdade\SolutionCaches
218 | LIVE_MONITOR
219 | LIVE_MONITOR
220 | DO_NOTHING
221 | LIVE_MONITOR
222 | LIVE_MONITOR
223 | LIVE_MONITOR
224 | LIVE_MONITOR
225 | LIVE_MONITOR
226 | LIVE_MONITOR
227 | LIVE_MONITOR
228 | LIVE_MONITOR
229 | DO_NOTHING
230 | LIVE_MONITOR
231 | True
232 | True
233 | True
234 | True
235 | True
236 | True
237 | True
238 | True
239 | True
240 | True
241 | True
242 | True
243 | True
244 | True
245 | True
246 | True
--------------------------------------------------------------------------------
/docs/nuget-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpatialFocus/EntityFrameworkCore.Extensions/2bb23618cb4c098aef2d15c5a081bb43f6c521e2/docs/nuget-icon.png
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/Data/DemoContext.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Data
7 | {
8 | using System;
9 | using Microsoft.EntityFrameworkCore;
10 | using SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Entities;
11 |
12 | public partial class DemoContext : DbContext
13 | {
14 | public DemoContext()
15 | {
16 | Database.EnsureDeleted();
17 | Database.EnsureCreated();
18 | }
19 |
20 | public DemoContext(DbContextOptions options)
21 | : base(options)
22 | {
23 | Database.EnsureDeleted();
24 | Database.EnsureCreated();
25 | }
26 |
27 | public DbSet Products { get; set; }
28 |
29 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
30 | {
31 | base.OnConfiguring(optionsBuilder);
32 |
33 | if (!optionsBuilder.IsConfigured)
34 | {
35 | optionsBuilder.UseSqlite("Data Source=demo.db");
36 | }
37 | }
38 |
39 | protected override void OnModelCreating(ModelBuilder modelBuilder)
40 | {
41 | // Any custom model configuration should come before calling ConfigureEnumLookup and ConfigureNames
42 | modelBuilder.Entity()
43 | .OwnsMany(nameof(Product.Reviews),
44 | builder =>
45 | {
46 | builder.ConfigureOwnedEnumLookup(EnumLookupOptions.Default.Pluralize().UseStringAsIdentifier(), modelBuilder);
47 | });
48 |
49 | modelBuilder.ConfigureEnumLookup(EnumLookupOptions.Default.Pluralize().UseStringAsIdentifier());
50 |
51 | modelBuilder.ConfigureNames(NamingOptions.Default.Pluralize()
52 | ////.SetTableNamingSource(NamingSource.ClrType)
53 | ////.SetNamingScheme(NamingScheme.SnakeCase)
54 | ////.OverrideTableNaming(NamingScheme.SnakeCase)
55 | .SkipTableNamingForGenericEntityTypes());
56 |
57 | modelBuilder.Entity()
58 | .HasData(
59 | new Product
60 | {
61 | ProductId = 1,
62 | ProductCategory = ProductCategory.Book,
63 | Name = "Robinson Crusoe",
64 | ReleaseDate = new DateTime(1719, 4, 25),
65 | Price = 14.99,
66 | },
67 | new Product
68 | {
69 | ProductId = 2,
70 | ProductCategory = ProductCategory.Bluray,
71 | Name = "Rogue One: A Star Wars Story",
72 | ReleaseDate = new DateTime(2017, 5, 4),
73 | Price = 11.99,
74 | },
75 | new Product
76 | {
77 | ProductId = 3,
78 | ProductCategory = ProductCategory.CD,
79 | Name = "Wham! - Last Christmas",
80 | ReleaseDate = new DateTime(1984, 12, 3),
81 | Price = 6.97,
82 | IdealForSpecialOccasion = SpecialOccasion.Christmas,
83 | });
84 | }
85 | }
86 | }
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/Entities/Product.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Entities
7 | {
8 | using System;
9 | using System.Collections.Generic;
10 |
11 | public class Product
12 | {
13 | public Product()
14 | {
15 | Created = DateTime.Now;
16 | }
17 |
18 | public DateTime Created { get; set; }
19 |
20 | public SpecialOccasion? IdealForSpecialOccasion { get; set; }
21 |
22 | public string Name { get; set; }
23 |
24 | public double Price { get; set; }
25 |
26 | public ProductCategory ProductCategory { get; set; }
27 |
28 | public int ProductId { get; set; }
29 |
30 | public DateTime ReleaseDate { get; set; }
31 |
32 | public List Reviews { get; set; }
33 | }
34 | }
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/Entities/ProductCategory.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Entities
7 | {
8 | public enum ProductCategory
9 | {
10 | Book = 1,
11 |
12 | Bluray,
13 |
14 | CD,
15 |
16 | DVD,
17 |
18 | Other,
19 | }
20 | }
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/Entities/Review.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Entities
7 | {
8 | public class Review
9 | {
10 | public ReviewRating Rating { get; set; }
11 | }
12 | }
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/Entities/ReviewRating.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Entities
7 | {
8 | public enum ReviewRating
9 | {
10 | Excellent = 1,
11 |
12 | Average,
13 |
14 | Bad,
15 | }
16 | }
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/Entities/SpecialOccasion.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Entities
7 | {
8 | using System.ComponentModel;
9 |
10 | public enum SpecialOccasion
11 | {
12 | [Description("Your birth anniversary")]
13 | Birthday = 1,
14 |
15 | [Description("Jesus' birth anniversary")]
16 | Christmas,
17 |
18 | [Description("Jesus' resurrection anniversary")]
19 | Easter,
20 |
21 | [Description("Florist holiday")]
22 | Valentines,
23 |
24 | [Description("Marriage anniversary")]
25 | WeddingDay,
26 | }
27 | }
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/Program.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo
7 | {
8 | using System;
9 | using System.Linq;
10 | using SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.Data;
11 |
12 | public class Program
13 | {
14 | private static void Main(string[] args)
15 | {
16 | using (DemoContext context = new DemoContext())
17 | {
18 | Console.WriteLine($"Found {context.Products.Count()} products.");
19 | }
20 |
21 | Console.WriteLine("--- press a key ---");
22 | Console.ReadKey();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/samples/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo/SpatialFocus.EntityFrameworkCore.Extensions.SQLiteDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/SpatialFocus.EntityFrameworkCore.Extensions/EnumLookupAttribute.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions
7 | {
8 | using System;
9 |
10 | public class EnumLookupAttribute : Attribute
11 | {
12 | }
13 | }
--------------------------------------------------------------------------------
/src/SpatialFocus.EntityFrameworkCore.Extensions/EnumLookupExtension.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Spatial Focus. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 | //
5 |
6 | namespace SpatialFocus.EntityFrameworkCore.Extensions
7 | {
8 | using System;
9 | using System.Collections.Generic;
10 | using System.ComponentModel;
11 | using System.Linq;
12 | using System.Reflection;
13 | using Microsoft.EntityFrameworkCore;
14 | using Microsoft.EntityFrameworkCore.Metadata;
15 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
16 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
17 |
18 | public static class EnumLookupExtension
19 | {
20 | public static void ConfigureEnumLookup(this ModelBuilder modelBuilder, EnumLookupOptions enumOptions)
21 | {
22 | foreach (IMutableProperty property in modelBuilder.Model.GetEntityTypes().SelectMany(x => x.GetProperties()).ToList())
23 | {
24 | IMutableEntityType entityType = property.DeclaringEntityType;
25 |
26 | if (entityType.IsOwned())
27 | {
28 | continue;
29 | }
30 |
31 | ConfigureEnumLookupForProperty(modelBuilder, enumOptions, property,
32 | (enumLookupEntityType) =>
33 | {
34 | modelBuilder.Entity(entityType.Name)
35 | .HasOne(enumLookupEntityType)
36 | .WithMany()
37 | .HasPrincipalKey("Id")
38 | .HasForeignKey(property.Name)
39 | .OnDelete(enumOptions.DeleteBehavior);
40 | }, (valueConverter) => { modelBuilder.Entity(entityType.Name).Property(property.Name).HasConversion(valueConverter); });
41 | }
42 | }
43 |
44 | public static void ConfigureOwnedEnumLookup(
45 | this OwnedNavigationBuilder ownedNavigationBuilder, EnumLookupOptions enumOptions,
46 | ModelBuilder modelBuilder) where TEntity : class where TDependentEntity : class
47 | {
48 | foreach (IMutableProperty property in ownedNavigationBuilder.OwnedEntityType.GetProperties().ToList())
49 | {
50 | ConfigureEnumLookupForProperty(modelBuilder, enumOptions, property,
51 | (enumLookupEntityType) =>
52 | {
53 | ownedNavigationBuilder.HasOne(enumLookupEntityType)
54 | .WithMany()
55 | .HasPrincipalKey("Id")
56 | .HasForeignKey(property.Name)
57 | .OnDelete(enumOptions.DeleteBehavior);
58 | }, (valueConverter) => { ownedNavigationBuilder.Property(property.Name).HasConversion(valueConverter); });
59 | }
60 | }
61 |
62 | public static string GetEnumDescription(Enum value)
63 | {
64 | FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
65 |
66 | DescriptionAttribute attribute = (DescriptionAttribute)fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute), true);
67 |
68 | return attribute?.Description;
69 | }
70 |
71 | // See https://github.com/aspnet/EntityFrameworkCore/issues/12248#issuecomment-395450990
72 | private static void ConfigureEnumLookupForProperty(ModelBuilder modelBuilder, EnumLookupOptions enumOptions,
73 | IMutableProperty property, Action configureEntityType, Action configureEntityTypeConversion)
74 | {
75 | Type propertyType = property.ClrType;
76 |
77 | if (ShouldSkip(propertyType, enumOptions))
78 | {
79 | return;
80 | }
81 |
82 | Type enumType = propertyType.GetEnumOrNullableEnumType();
83 |
84 | Dictionary enumValueDescriptions = GetEnumValueDescriptions(enumType);
85 |
86 | bool usesDescription = enumValueDescriptions.Values.Any(x => x != null);
87 |
88 | Type enumLookupEntityType = GetEnumLookupEntityType(enumOptions, usesDescription, enumType);
89 | bool shouldSkipEnumLookupTableConfiguration = modelBuilder.Model.FindEntityType(enumLookupEntityType) != null;
90 |
91 | configureEntityType(enumLookupEntityType);
92 |
93 | ValueConverter valueConverter = GetValueConverter(enumType);
94 |
95 | if (!enumOptions.UseNumberLookup)
96 | {
97 | configureEntityTypeConversion(valueConverter);
98 | }
99 |
100 | if (shouldSkipEnumLookupTableConfiguration)
101 | {
102 | return;
103 | }
104 |
105 | EntityTypeBuilder enumLookupBuilder = modelBuilder.Entity(enumLookupEntityType);
106 | ConfigureEnumLookupTable(enumLookupBuilder, enumOptions, enumType);
107 |
108 | if (enumOptions.UseNumberLookup)
109 | {
110 | modelBuilder.Entity(enumLookupEntityType).HasIndex("Name").IsUnique();
111 | }
112 | else
113 | {
114 | modelBuilder.Entity(enumLookupEntityType).Property("Id").HasConversion(valueConverter);
115 | }
116 |
117 | // TODO: Check status of https://github.com/aspnet/EntityFrameworkCore/issues/12194 before using migrations
118 | enumLookupBuilder.HasData(GetEnumData(enumType, enumLookupEntityType, enumOptions.UseNumberLookup, usesDescription,
119 | enumValueDescriptions));
120 | }
121 |
122 | private static void ConfigureEnumLookupTable(EntityTypeBuilder enumLookupBuilder, EnumLookupOptions enumOptions, Type enumType)
123 | {
124 | string typeName = enumType.Name;
125 | string tableName = enumOptions.NamingFunction(typeName);
126 | enumLookupBuilder.ToTable(tableName);
127 | }
128 |
129 | private static object[] GetEnumData(Type enumType, Type concreteType, bool useNumberLookup, bool usesDescription,
130 | Dictionary enumValueDescriptions)
131 | {
132 | return Enum.GetValues(enumType)
133 | .OfType