├── .editorconfig ├── .gitignore ├── Build ├── SetVersion.ps1 ├── linq2db.Default.props ├── linq2db.Tests.props └── linq2db.snk ├── MIT-LICENSE.txt ├── NuGet.config ├── NuGet ├── BuildNuspecs.ps1 ├── icon.png └── linq2db.EntityFrameworkCore.nuspec ├── README.md ├── Source ├── .editorconfig └── LinqToDB.EntityFrameworkCore │ ├── EFConnectionInfo.cs │ ├── EFCoreMetadataReader.cs │ ├── EFProviderInfo.cs │ ├── ILinqToDBForEFTools.cs │ ├── Internal │ ├── EFCoreExpressionAttribute.cs │ └── LinqToDBForEFQueryProvider.cs │ ├── LinqToDBExtensionsAdapter.cs │ ├── LinqToDBForEFExtensions.Async.EF.cs │ ├── LinqToDBForEFExtensions.Async.cs │ ├── LinqToDBForEFTools.ContextExtensions.cs │ ├── LinqToDBForEFTools.Extensions.cs │ ├── LinqToDBForEFTools.Mapping.cs │ ├── LinqToDBForEFTools.cs │ ├── LinqToDBForEFToolsDataConnection.cs │ ├── LinqToDBForEFToolsDataContext.cs │ ├── LinqToDBForEFToolsException.cs │ ├── LinqToDBForEFToolsImplDefault.cs │ ├── LinqToDBProviderInfo.cs │ ├── Properties │ └── JetBrains.Annotations.cs │ └── linq2db.EntityFrameworkCore.csproj ├── Tests ├── LinqToDB.EntityFrameworkCore.BaseTests │ ├── LinqToDB.EntityFrameworkCore.BaseTests.csproj │ ├── Logging │ │ ├── LogMessageEntry.cs │ │ ├── NullExternalScopeProvider.cs │ │ ├── NullScope.cs │ │ ├── TestLogger.cs │ │ ├── TestLoggerExtensions.cs │ │ └── TestLoggerProvider.cs │ ├── Models │ │ └── Northwind │ │ │ ├── BaseEntity.cs │ │ │ ├── Category.cs │ │ │ ├── Customer.cs │ │ │ ├── CustomerCustomerDemo.cs │ │ │ ├── CustomerDemographics.cs │ │ │ ├── CustomerOrderHistory.cs │ │ │ ├── CustomerQuery.cs │ │ │ ├── CustomerView.cs │ │ │ ├── Employee.cs │ │ │ ├── EmployeeTerritory.cs │ │ │ ├── NorthwindData.Objects.cs │ │ │ ├── NorthwindData.cs │ │ │ ├── Order.cs │ │ │ ├── OrderDetail.cs │ │ │ ├── Product.cs │ │ │ ├── Region.cs │ │ │ ├── Shipper.cs │ │ │ ├── Supplier.cs │ │ │ └── Territory.cs │ ├── TestUtils.cs │ └── TestsBase.cs ├── LinqToDB.EntityFrameworkCore.PomeloMySql.Tests │ ├── LinqToDB.EntityFrameworkCore.PomeloMySql.Tests.csproj │ ├── Models │ │ ├── Northwind.Mapping │ │ │ ├── CategoriesMap.cs │ │ │ ├── CustomerCustomerDemoMap.cs │ │ │ ├── CustomerDemographicsMap.cs │ │ │ ├── CustomersMap.cs │ │ │ ├── EmployeeTerritoriesMap.cs │ │ │ ├── EmployeesMap.cs │ │ │ ├── OrderDetailsMap.cs │ │ │ ├── OrderMap.cs │ │ │ ├── ProductsMap.cs │ │ │ ├── RegionMap.cs │ │ │ ├── ShippersMap.cs │ │ │ ├── SuppliersMap.cs │ │ │ └── TerritoriesMap.cs │ │ └── Northwind │ │ │ └── NorthwindContext.cs │ └── PomeloMySqlTests.cs ├── LinqToDB.EntityFrameworkCore.PostgreSQL.Tests │ ├── LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.csproj │ ├── Models │ │ └── NpgSqlEntities │ │ │ ├── Event.cs │ │ │ ├── EventView.cs │ │ │ └── NpgSqlEnititesContext.cs │ ├── NpgSqlTests.cs │ └── SampleTests │ │ ├── AAA.cs │ │ ├── Child.cs │ │ ├── DataContextExtensions.cs │ │ ├── Detail.cs │ │ ├── Entity.cs │ │ ├── Entity2Item.cs │ │ ├── IHasId.cs │ │ ├── Id.cs │ │ ├── IdTests.cs │ │ ├── IdValueConverter.cs │ │ ├── Item.cs │ │ ├── ModelBuilderExtensions.cs │ │ ├── QueryableExtensions.cs │ │ ├── StringExtensions.cs │ │ ├── SubDetail.cs │ │ └── TypeExtensions.cs ├── LinqToDB.EntityFrameworkCore.SQLite.Tests │ ├── LinqToDB.EntityFrameworkCore.SQLite.Tests.csproj │ ├── Models │ │ ├── Northwind.Mapping │ │ │ ├── CategoriesMap.cs │ │ │ ├── CustomerCustomerDemoMap.cs │ │ │ ├── CustomerDemographicsMap.cs │ │ │ ├── CustomersMap.cs │ │ │ ├── EmployeeTerritoriesMap.cs │ │ │ ├── EmployeesMap.cs │ │ │ ├── OrderDetailsMap.cs │ │ │ ├── OrderMap.cs │ │ │ ├── ProductsMap.cs │ │ │ ├── RegionMap.cs │ │ │ ├── ShippersMap.cs │ │ │ ├── SuppliersMap.cs │ │ │ └── TerritoriesMap.cs │ │ └── Northwind │ │ │ └── NorthwindContext.cs │ └── SQLiteTests.cs └── LinqToDB.EntityFrameworkCore.SqlServer.Tests │ ├── IssueTests.cs │ ├── JsonConverTests.cs │ ├── LinqToDB.EntityFrameworkCore.SqlServer.Tests.csproj │ ├── Models │ ├── IssueModel │ │ ├── Issue73Entity.cs │ │ └── IssueContext.cs │ ├── Northwind.Mapping │ │ ├── BaseEntityMap.cs │ │ ├── CategoriesMap.cs │ │ ├── CustomerCustomerDemoMap.cs │ │ ├── CustomerDemographicsMap.cs │ │ ├── CustomersMap.cs │ │ ├── EmployeeTerritoriesMap.cs │ │ ├── EmployeesMap.cs │ │ ├── OrderDetailsMap.cs │ │ ├── OrderMap.cs │ │ ├── ProductsMap.cs │ │ ├── RegionMap.cs │ │ ├── ShippersMap.cs │ │ ├── SuppliersMap.cs │ │ └── TerritoriesMap.cs │ └── Northwind │ │ └── NorthwindContext.cs │ ├── QueryableExtensions.cs │ ├── ToolsTests.cs │ └── ValueConversion │ ├── ConvertorTests.cs │ ├── IEntity`1.cs │ ├── IdValueConverterSelector.cs │ ├── IdValueConverter`2.cs │ ├── Id`2.cs │ └── SubDivision.cs ├── azure-pipelines.yml ├── linq2db.EFCore.sln └── linq2db.EFCore.sln.DotSettings /.gitignore: -------------------------------------------------------------------------------- 1 | #ignore thumbnails created by windows 2 | Thumbs.db 3 | #Ignore files build by Visual Studio 4 | *.obj 5 | *.pdb 6 | *.user 7 | *.aps 8 | *.pch 9 | *.vspscc 10 | *_i.c 11 | *_p.c 12 | *.ncb 13 | *.suo 14 | *.tlb 15 | *.tlh 16 | *.bak 17 | *.cache 18 | *.ilk 19 | *.log 20 | *.cs.ide 21 | [Bb]in 22 | [Dd]ebug*/ 23 | *.lib 24 | *.sbr 25 | obj/ 26 | [Rr]elease*/ 27 | _ReSharper*/ 28 | [Tt]est[Rr]esult* 29 | linq2db.sln.docstates 30 | Tests/**/UserDataProviders*.* 31 | NuGet/*.nupkg 32 | !*.dll 33 | !*.exe 34 | !*.pdb 35 | linq2db.sln.ide/graph 36 | linq2db.sln.ide/ 37 | !Redist/** 38 | /packages 39 | /.vs/* 40 | *.lock.json 41 | /api 42 | /linq2db.github.io 43 | #cake 44 | /tools 45 | /.tools 46 | /.idea/ 47 | -------------------------------------------------------------------------------- /Build/SetVersion.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$true)][string]$path, 3 | [Parameter(Mandatory=$true)][string]$version 4 | ) 5 | 6 | $ErrorActionPreference = "Stop" 7 | Set-StrictMode -Version Latest 8 | 9 | if ($version) { 10 | 11 | $xmlPath = Resolve-Path "$path" 12 | 13 | $xml = [XML](Get-Content "$xmlPath") 14 | $xml.PreserveWhitespace = $true 15 | $save = $false 16 | 17 | $xPath = "//PropertyGroup/Version" 18 | $nodes = $xml.SelectNodes($xPath) 19 | foreach($node in $nodes) { 20 | $node.InnerXml = $version 21 | $save = $true 22 | } 23 | 24 | if ($save) { 25 | Write-Host "Patched $xmlPath" 26 | $xml.Save($xmlPath) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Build/linq2db.Default.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 5.1.6 4 | 5 | Svyatoslav Danyliv, Igor Tkachev, Dmitry Lukashenko, Ilya Chudin 6 | Linq to DB 7 | linq2db.net 8 | 2002-2020 linq2db.net 9 | https://github.com/linq2db/linq2db.EntityFrameworkCore 10 | git 11 | 12 | 9.0 13 | enable 14 | 4 15 | prompt 16 | preview 17 | 18 | false 19 | false 20 | True 21 | ..\..\Build\linq2db.snk 22 | False 23 | 24 | true 25 | true 26 | true 27 | true 28 | true 29 | true 30 | false 31 | 32 | 33 | 34 | preview 35 | 36 | false 37 | false 38 | 39 | 40 | true 41 | true 42 | 43 | 44 | -------------------------------------------------------------------------------- /Build/linq2db.Tests.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | netcoreapp3.1 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Build/linq2db.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/linq2db.EntityFrameworkCore/81b82c1acbe56fa33d00a4818ac5592d6e75f187/Build/linq2db.snk -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /NuGet/BuildNuspecs.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$true)][string]$path, 3 | [Parameter(Mandatory=$true)][string]$version, 4 | [Parameter(Mandatory=$false)][string]$branch 5 | ) 6 | 7 | $ErrorActionPreference = "Stop" 8 | Set-StrictMode -Version Latest 9 | 10 | if ($version) { 11 | 12 | $nsUri = 'http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd' 13 | $ns = @{ns=$nsUri} 14 | $commit = (git rev-parse HEAD) 15 | if (-not $branch) { 16 | $branch = (git rev-parse --abbrev-ref HEAD) 17 | } 18 | 19 | Get-ChildItem $path | ForEach { 20 | $xmlPath = Resolve-Path $_.FullName 21 | 22 | $xml = [xml] (Get-Content "$xmlPath") 23 | $xml.PreserveWhitespace = $true 24 | 25 | # set version metadata 26 | $child = $xml.CreateElement('version', $nsUri) 27 | $child.InnerText = $version 28 | $xml.package.metadata.AppendChild($child) 29 | 30 | # set repository/commit link 31 | $child = $xml.CreateElement('repository', $nsUri) 32 | $attr = $xml.CreateAttribute('type') 33 | $attr.Value = 'git' 34 | $child.Attributes.Append($attr) 35 | $attr = $xml.CreateAttribute('url') 36 | $attr.Value = 'https://github.com/linq2db/linq2db.EntityFrameworkCore.git' 37 | $child.Attributes.Append($attr) 38 | $attr = $xml.CreateAttribute('branch') 39 | $attr.Value = $branch 40 | $child.Attributes.Append($attr) 41 | $attr = $xml.CreateAttribute('commit') 42 | $attr.Value = $commit 43 | $child.Attributes.Append($attr) 44 | $xml.package.metadata.AppendChild($child) 45 | 46 | $xml.Save($xmlPath) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /NuGet/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ualehosaini/linq2db.EntityFrameworkCore/81b82c1acbe56fa33d00a4818ac5592d6e75f187/NuGet/icon.png -------------------------------------------------------------------------------- /NuGet/linq2db.EntityFrameworkCore.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | linq2db.EntityFrameworkCore 5 | Linq to DB (linq2db) extensions for Entity Framework Core 6 | Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko 7 | Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko 8 | Copyright © 2020 Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko 9 | Allows to execute Linq to DB (linq2db) queries in Entity Framework Core DbContext. 10 | 11 | linq linq2db LinqToDB ORM database entity-framework-core EntityFrameworkCore EFCore DB SQL SqlServer SqlCe SqlServerCe MySql Firebird SQLite Oracle ODP PostgreSQL DB2 12 | false 13 | images\icon.png 14 | https://github.com/linq2db/linq2db.EntityFrameworkCore 15 | MIT-LICENSE.txt 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Source/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | dotnet_diagnostic.CA1827.severity = error # CA1827: Do not use Count/LongCount when Any can be used 3 | dotnet_diagnostic.CA2007.severity = error # CA2007: Do not directly await a Task 4 | dotnet_diagnostic.CA1829.severity = error # CA1829: Use Length/Count property instead of Enumerable.Count method 5 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/EFConnectionInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | 3 | namespace LinqToDB.EntityFrameworkCore 4 | { 5 | /// 6 | /// Contains database connectivity information, extracted from EF.Core. 7 | /// 8 | public class EFConnectionInfo 9 | { 10 | /// 11 | /// Gets or sets database connection instance. 12 | /// 13 | public DbConnection? Connection { get; set; } 14 | 15 | /// 16 | /// Gets or sets database connection string. 17 | /// 18 | public string? ConnectionString { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/EFProviderInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | 6 | namespace LinqToDB.EntityFrameworkCore 7 | { 8 | /// 9 | /// Required integration information about underlying database provider, extracted from EF.Core. 10 | /// 11 | public class EFProviderInfo 12 | { 13 | /// 14 | /// Gets or sets database connection instance. 15 | /// 16 | public DbConnection? Connection { get; set; } 17 | 18 | /// 19 | /// Gets or sets EF.Core context instance. 20 | /// 21 | public DbContext? Context { get; set; } 22 | 23 | /// 24 | /// Gets or sets EF.Core context options instance. 25 | /// 26 | public IDbContextOptions? Options { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/ILinqToDBForEFTools.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Linq.Expressions; 3 | 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Diagnostics; 6 | using Microsoft.EntityFrameworkCore.Infrastructure; 7 | using Microsoft.EntityFrameworkCore.Metadata; 8 | using Microsoft.EntityFrameworkCore.Query; 9 | using Microsoft.EntityFrameworkCore.Storage; 10 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 11 | using Microsoft.Extensions.Logging; 12 | 13 | namespace LinqToDB.EntityFrameworkCore 14 | { 15 | using DataProvider; 16 | using Mapping; 17 | using Metadata; 18 | using Data; 19 | 20 | /// 21 | /// Interface for EF.Core - LINQ To DB integration bridge. 22 | /// 23 | public interface ILinqToDBForEFTools 24 | { 25 | /// 26 | /// Clears internal caches 27 | /// 28 | void ClearCaches(); 29 | 30 | /// 31 | /// Returns LINQ To DB provider, based on provider data from EF.Core. 32 | /// 33 | /// Provider information, extracted from EF.Core. 34 | /// Database connection information. 35 | /// LINQ TO DB provider instance. 36 | IDataProvider? GetDataProvider(EFProviderInfo providerInfo, EFConnectionInfo connectionInfo); 37 | 38 | /// 39 | /// Creates metadata provider for specified EF.Core data model. 40 | /// 41 | /// EF.Core data model. 42 | /// 43 | /// 44 | /// 45 | /// LINQ To DB metadata provider for specified EF.Core model. Can return null. 46 | IMetadataReader? CreateMetadataReader( 47 | IModel? model, 48 | RelationalSqlTranslatingExpressionVisitorDependencies? dependencies, 49 | IRelationalTypeMappingSource? mappingSource, 50 | IDiagnosticsLogger? logger); 51 | 52 | /// 53 | /// Creates mapping schema using provided EF.Core data model and metadata provider. 54 | /// 55 | /// EF.Core data model. 56 | /// Additional optional LINQ To DB database metadata provider. 57 | /// EF Core registry for type conversion. 58 | /// Mapping schema for provided EF.Core model. 59 | MappingSchema CreateMappingSchema(IModel model, IMetadataReader metadataReader, IValueConverterSelector convertorSelector); 60 | 61 | /// 62 | /// Returns mapping schema using provided EF.Core data model and metadata provider. 63 | /// 64 | /// EF.Core data model. 65 | /// Additional optional LINQ To DB database metadata provider. 66 | /// EF Core registry for type conversion. 67 | /// Mapping schema for provided EF.Core model. 68 | MappingSchema GetMappingSchema(IModel model, IMetadataReader? metadataReader, IValueConverterSelector? convertorSelector); 69 | 70 | /// 71 | /// Returns EF.Core for specific instance. 72 | /// 73 | /// EF.Core instance. 74 | /// instance. 75 | IDbContextOptions? GetContextOptions(DbContext? context); 76 | 77 | /// 78 | /// Transforms EF.Core expression tree to LINQ To DB expression. 79 | /// 80 | /// EF.Core expression tree. 81 | /// LINQ To DB instance. 82 | /// Optional DbContext instance. 83 | /// EF.Core data model instance. 84 | /// Transformed expression. 85 | Expression TransformExpression(Expression expression, IDataContext dc, DbContext? ctx, IModel? model); 86 | 87 | /// 88 | /// Extracts instance from object. 89 | /// 90 | /// EF.Core query. 91 | /// Current instance. 92 | DbContext? GetCurrentContext(IQueryable query); 93 | 94 | /// 95 | /// Extracts EF.Core connection information object from . 96 | /// 97 | /// instance. 98 | /// EF.Core connection data. 99 | EFConnectionInfo ExtractConnectionInfo(IDbContextOptions? options); 100 | 101 | /// 102 | /// Extracts EF.Core data model instance from . 103 | /// 104 | /// instance. 105 | /// EF.Core data model instance. 106 | IModel? ExtractModel(IDbContextOptions? options); 107 | 108 | /// 109 | /// Creates logger used for logging Linq To DB connection calls. 110 | /// 111 | /// instance. 112 | /// Logger instance. 113 | ILogger? CreateLogger(IDbContextOptions? options); 114 | 115 | /// 116 | /// Logs DataConnection information. 117 | /// 118 | /// 119 | /// 120 | void LogConnectionTrace(TraceInfo info, ILogger logger); 121 | 122 | /// 123 | /// Enables attaching entities to change tracker. 124 | /// Entities will be attached only if AsNoTracking() is not used in query and DbContext is configured to track entities. 125 | /// 126 | bool EnableChangeTracker { get; set; } 127 | 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/Internal/EFCoreExpressionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using LinqToDB.Mapping; 6 | using LinqToDB.SqlQuery; 7 | 8 | namespace LinqToDB.EntityFrameworkCore.Internal 9 | { 10 | /// 11 | /// Maps linq2db exression. 12 | /// 13 | public class EFCoreExpressionAttribute : Sql.ExpressionAttribute 14 | { 15 | /// 16 | /// Creates instance of expression mapper. 17 | /// 18 | /// Mapped expression. 19 | public EFCoreExpressionAttribute(string expression) : base(expression) 20 | { 21 | } 22 | 23 | /// 24 | public override ISqlExpression GetExpression( 25 | IDataContext dataContext, 26 | SelectQuery query, 27 | Expression expression, 28 | Func converter) 29 | { 30 | var knownExpressions = new List(); 31 | if (expression.NodeType == ExpressionType.Call) 32 | { 33 | var mc = (MethodCallExpression) expression; 34 | if (!mc.Method.IsStatic) 35 | knownExpressions.Add(mc.Object); 36 | knownExpressions.AddRange(mc.Arguments); 37 | } 38 | else 39 | { 40 | var me = (MemberExpression) expression; 41 | knownExpressions.Add(me.Expression); 42 | } 43 | 44 | var pams = new List(knownExpressions.Select(_ => (ISqlExpression?) null)); 45 | 46 | _ = Sql.ExtensionAttribute.ResolveExpressionValues(Expression!, 47 | (v, d) => 48 | { 49 | var idx = int.Parse(v); 50 | 51 | if (pams[idx] == null) 52 | pams[idx] = converter(knownExpressions[idx], null); 53 | 54 | return v; 55 | }); 56 | 57 | var parameters = pams.Select(p => p ?? new SqlExpression("!!!")).ToArray(); 58 | return new SqlExpression(expression.Type, Expression!, Precedence, parameters); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/Internal/LinqToDBForEFQueryProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | using Microsoft.EntityFrameworkCore.Query; 11 | using LinqToDB.Expressions; 12 | 13 | namespace LinqToDB.EntityFrameworkCore.Internal 14 | { 15 | using Async; 16 | using Linq; 17 | 18 | /// 19 | /// Adapter for 20 | /// This is internal API and is not intended for use by Linq To DB applications. 21 | /// It may change or be removed without further notice. 22 | /// 23 | /// Type of query element. 24 | public class LinqToDBForEFQueryProvider : IAsyncQueryProvider, IQueryProviderAsync, IQueryable, IAsyncEnumerable 25 | { 26 | /// 27 | /// Creates instance of adapter. 28 | /// 29 | /// Data context instance. 30 | /// Query expression. 31 | public LinqToDBForEFQueryProvider(IDataContext dataContext, Expression expression) 32 | { 33 | if (expression == null) throw new ArgumentNullException(nameof(expression)); 34 | var dataContext1 = dataContext ?? throw new ArgumentNullException(nameof(dataContext)); 35 | QueryProvider = (IQueryProviderAsync) Internals.CreateExpressionQueryInstance(dataContext1, expression); 36 | QueryProviderAsQueryable = (IQueryable) QueryProvider; 37 | } 38 | 39 | IQueryProviderAsync QueryProvider { get; } 40 | IQueryable QueryProviderAsQueryable { get; } 41 | 42 | /// 43 | /// Creates instance from query expression. 44 | /// 45 | /// Query expression. 46 | /// instance. 47 | public IQueryable CreateQuery(Expression expression) 48 | { 49 | return QueryProvider.CreateQuery(expression); 50 | } 51 | 52 | /// 53 | /// Creates instance from query expression. 54 | /// 55 | /// Query element type. 56 | /// Query expression. 57 | /// instance. 58 | public IQueryable CreateQuery(Expression expression) 59 | { 60 | return QueryProvider.CreateQuery(expression); 61 | } 62 | 63 | /// 64 | /// Executes query expression. 65 | /// 66 | /// Query expression. 67 | /// Query result. 68 | public object Execute(Expression expression) 69 | { 70 | return QueryProvider.Execute(expression); 71 | } 72 | 73 | /// 74 | /// Executes query expression and returns typed result. 75 | /// 76 | /// Type of result. 77 | /// Query expression. 78 | /// Query result. 79 | public TResult Execute(Expression expression) 80 | { 81 | return QueryProvider.Execute(expression); 82 | } 83 | 84 | private static readonly MethodInfo _executeAsyncMethodInfo = 85 | MemberHelper.MethodOf((IQueryProviderAsync p) => p.ExecuteAsync(null!, default)).GetGenericMethodDefinition(); 86 | 87 | /// 88 | /// Executes query expression and returns result as value. 89 | /// 90 | /// Type of result element. 91 | /// Query expression. 92 | /// Cancellation token. 93 | /// Query result as . 94 | public Task> ExecuteAsyncEnumerable(Expression expression, CancellationToken token) 95 | { 96 | return QueryProvider.ExecuteAsyncEnumerable(expression, token); 97 | } 98 | 99 | /// 100 | /// Executes query expression and returns typed result. 101 | /// 102 | /// Type of result. 103 | /// Query expression. 104 | /// Cancellation token. 105 | /// Query result. 106 | TResult IAsyncQueryProvider.ExecuteAsync(Expression expression, CancellationToken cancellationToken) 107 | { 108 | var item = typeof(TResult).GetGenericArguments()[0]; 109 | var method = _executeAsyncMethodInfo.MakeGenericMethod(item); 110 | return (TResult) method.Invoke(QueryProvider, new object[] { expression, cancellationToken }); 111 | } 112 | 113 | /// 114 | /// Executes query expression and returns typed result. 115 | /// 116 | /// Type of result. 117 | /// Query expression. 118 | /// Cancellation token. 119 | /// Query result. 120 | public Task ExecuteAsync(Expression expression, CancellationToken cancellationToken) 121 | { 122 | return QueryProvider.ExecuteAsync(expression, cancellationToken); 123 | } 124 | 125 | IEnumerator IEnumerable.GetEnumerator() 126 | { 127 | return QueryProviderAsQueryable.GetEnumerator(); 128 | } 129 | 130 | IEnumerator IEnumerable.GetEnumerator() 131 | { 132 | return QueryProviderAsQueryable.GetEnumerator(); 133 | } 134 | 135 | #region IQueryable 136 | 137 | /// 138 | /// Type of query element. 139 | /// 140 | public Type ElementType => typeof(T); 141 | 142 | /// 143 | /// Query expression. 144 | /// 145 | public Expression Expression => QueryProviderAsQueryable.Expression; 146 | 147 | /// 148 | /// Query provider. 149 | /// 150 | public IQueryProvider Provider => this; 151 | 152 | #endregion 153 | 154 | /// 155 | /// Gets for current query. 156 | /// 157 | /// Cancellation token. 158 | /// Query result as . 159 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken) 160 | { 161 | return QueryProvider.ExecuteAsyncEnumerable(Expression, cancellationToken).Result.GetAsyncEnumerator(cancellationToken); 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFTools.Extensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace LinqToDB.EntityFrameworkCore 4 | { 5 | public static partial class LinqToDBForEFTools 6 | { 7 | /// 8 | /// Converts EF.Core instance to LINQ To DB instance. 9 | /// 10 | /// Mapping entity type. 11 | /// EF.Core instance. 12 | /// LINQ To DB instance. 13 | public static ITable ToLinqToDBTable(this DbSet dbSet) 14 | where T : class 15 | { 16 | var context = Implementation.GetCurrentContext(dbSet); 17 | if (context == null) 18 | throw new LinqToDBForEFToolsException($"Can not load current context from {nameof(dbSet)}"); 19 | 20 | var dc = CreateLinqToDbContext(context); 21 | return dc.GetTable(); 22 | } 23 | 24 | /// 25 | /// Converts EF.Core instance to LINQ To DB instance 26 | /// using existing LINQ To DB instance. 27 | /// 28 | /// Mapping entity type. 29 | /// EF.Core instance. 30 | /// LINQ To DB data context instance. 31 | /// LINQ To DB instance. 32 | public static ITable ToLinqToDBTable(this DbSet dbSet, IDataContext dataContext) 33 | where T : class 34 | { 35 | return dataContext.GetTable(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFTools.Mapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace LinqToDB.EntityFrameworkCore 9 | { 10 | using Expressions; 11 | using Extensions; 12 | 13 | public partial class LinqToDBForEFTools 14 | { 15 | 16 | static void InitializeMapping() 17 | { 18 | Linq.Expressions.MapMember( 19 | (DbFunctions f, string m, string p) => f.Like(m, p), (f, m, p) => Sql.Like(m, p)); 20 | 21 | // InitializeSqlServerMapping(); 22 | } 23 | 24 | 25 | #region Sql Server 26 | 27 | static Sql.DateParts? GetDatePart(string name) 28 | { 29 | switch (name) 30 | { 31 | case "Year" : return Sql.DateParts.Year; 32 | case "Day" : return Sql.DateParts.Day; 33 | case "Month" : return Sql.DateParts.Month; 34 | case "Hour" : return Sql.DateParts.Hour; 35 | case "Minute" : return Sql.DateParts.Minute; 36 | case "Second" : return Sql.DateParts.Second; 37 | case "Millisecond": return Sql.DateParts.Millisecond; 38 | } 39 | 40 | return null; 41 | } 42 | 43 | /// 44 | /// Initilaizes SQL Server's DbFunctions dynamically to avoid dependency 45 | /// 46 | static void InitializeSqlServerMapping() 47 | { 48 | var type = Type.GetType("Microsoft.EntityFrameworkCore.SqlServerDbFunctionsExtensions, Microsoft.EntityFrameworkCore.SqlServer", false); 49 | 50 | if (type == null) 51 | return; 52 | 53 | var sqlServerMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Static) 54 | .Where(m => m.GetParameters().Length > 0) 55 | .ToArray(); 56 | 57 | var dbFunctionsParameter = Expression.Parameter(typeof(DateTime), "dbFunctions"); 58 | 59 | var dateDiffStr = "DateDiff"; 60 | var dateDiffMethods = sqlServerMethods.Where(m => m.Name.StartsWith(dateDiffStr)).ToArray(); 61 | 62 | var dateDiffMethod = MemberHelper.MethodOf(() => Sql.DateDiff(Sql.DateParts.Day, null, null)); 63 | 64 | foreach (var method in dateDiffMethods) 65 | { 66 | var datePart = GetDatePart(method.Name.Substring(dateDiffStr.Length)); 67 | if (datePart == null) 68 | continue; 69 | 70 | var parameters = method.GetParameters(); 71 | if (parameters.Length < 3) 72 | continue; 73 | 74 | var boundaryType = parameters[1].ParameterType; 75 | if (boundaryType.ToUnderlying() != typeof(DateTime)) 76 | continue; 77 | 78 | var startParameter = Expression.Parameter(boundaryType, "start"); 79 | var endParameter = Expression.Parameter(boundaryType, "end"); 80 | 81 | var startExpr = startParameter.Type != typeof(DateTime?) 82 | ? (Expression) Expression.Convert(startParameter, typeof(DateTime?)) 83 | : startParameter; 84 | 85 | var endExpr = endParameter.Type != typeof(DateTime?) 86 | ? (Expression) Expression.Convert(endParameter, typeof(DateTime?)) 87 | : endParameter; 88 | 89 | 90 | var body = Expression.Call(dateDiffMethod, Expression.Constant(datePart.Value), startExpr, endExpr); 91 | var lambda = Expression.Lambda(body, dbFunctionsParameter, startParameter, endParameter); 92 | 93 | Linq.Expressions.MapMember(method, lambda); 94 | } 95 | } 96 | 97 | #endregion 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFToolsDataConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | 8 | using Microsoft.EntityFrameworkCore; 9 | using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; 10 | using Microsoft.EntityFrameworkCore.Infrastructure; 11 | using Microsoft.EntityFrameworkCore.Storage; 12 | 13 | namespace LinqToDB.EntityFrameworkCore 14 | { 15 | using System.Diagnostics.CodeAnalysis; 16 | using Data; 17 | using DataProvider; 18 | using Linq; 19 | 20 | /// 21 | /// linq2db EF.Core data connection. 22 | /// 23 | public class LinqToDBForEFToolsDataConnection : DataConnection, IExpressionPreprocessor 24 | { 25 | readonly IModel? _model; 26 | readonly Func? _transformFunc; 27 | 28 | private IEntityType? _lastEntityType; 29 | private Type? _lastType; 30 | private IStateManager? _stateManager; 31 | 32 | /// 33 | /// Change tracker enable flag. 34 | /// 35 | public bool Tracking { get; set; } 36 | 37 | /// 38 | /// EF.Core database context. 39 | /// 40 | public DbContext? Context { get; } 41 | 42 | /// 43 | /// Creates new instance of data connection. 44 | /// 45 | /// EF.Core database context. 46 | /// linq2db database provider. 47 | /// Connection string. 48 | /// EF.Core data model. 49 | /// Expression converter. 50 | public LinqToDBForEFToolsDataConnection( 51 | DbContext? context, 52 | [NotNull] IDataProvider dataProvider, 53 | [NotNull] string connectionString, 54 | IModel? model, 55 | Func? transformFunc) : base(dataProvider, connectionString) 56 | { 57 | Context = context; 58 | _model = model; 59 | _transformFunc = transformFunc; 60 | CopyDatabaseProperties(); 61 | if (LinqToDBForEFTools.EnableChangeTracker) 62 | OnEntityCreated += OnEntityCreatedHandler; 63 | } 64 | 65 | /// 66 | /// Creates new instance of data connection. 67 | /// 68 | /// EF.Core database context. 69 | /// linq2db database provider. 70 | /// Database transaction. 71 | /// EF.Core data model. 72 | /// Expression converter. 73 | public LinqToDBForEFToolsDataConnection( 74 | DbContext? context, 75 | [NotNull] IDataProvider dataProvider, 76 | [NotNull] IDbTransaction transaction, 77 | IModel? model, 78 | Func? transformFunc 79 | ) : base(dataProvider, transaction) 80 | { 81 | Context = context; 82 | _model = model; 83 | _transformFunc = transformFunc; 84 | CopyDatabaseProperties(); 85 | if (LinqToDBForEFTools.EnableChangeTracker) 86 | OnEntityCreated += OnEntityCreatedHandler; 87 | } 88 | 89 | /// 90 | /// Creates new instance of data connection. 91 | /// 92 | /// EF.Core database context. 93 | /// linq2db database provider. 94 | /// Database connection instance. 95 | /// EF.Core data model. 96 | /// Expression converter. 97 | public LinqToDBForEFToolsDataConnection( 98 | DbContext? context, 99 | [NotNull] IDataProvider dataProvider, 100 | [NotNull] IDbConnection connection, 101 | IModel? model, 102 | Func? transformFunc) : base(dataProvider, connection) 103 | { 104 | Context = context; 105 | _model = model; 106 | _transformFunc = transformFunc; 107 | CopyDatabaseProperties(); 108 | if (LinqToDBForEFTools.EnableChangeTracker) 109 | OnEntityCreated += OnEntityCreatedHandler; 110 | } 111 | 112 | /// 113 | /// Converts expression using convert function, passed to context. 114 | /// 115 | /// Expression to convert. 116 | /// Converted expression. 117 | public Expression ProcessExpression(Expression expression) 118 | { 119 | if (_transformFunc == null) 120 | return expression; 121 | return _transformFunc(expression, this, Context, _model); 122 | } 123 | 124 | private void OnEntityCreatedHandler(EntityCreatedEventArgs args) 125 | { 126 | if (!LinqToDBForEFTools.EnableChangeTracker 127 | || !Tracking 128 | || Context!.ChangeTracker.QueryTrackingBehavior == QueryTrackingBehavior.NoTracking) 129 | return; 130 | 131 | var type = args.Entity.GetType(); 132 | if (_lastType != type) 133 | { 134 | _lastType = type; 135 | _lastEntityType = Context.Model.FindEntityType(type); 136 | } 137 | 138 | if (_lastEntityType == null) 139 | return; 140 | 141 | if (_stateManager == null) 142 | _stateManager = Context.GetService(); 143 | 144 | 145 | // It is a real pain to register entity in change tracker 146 | // 147 | InternalEntityEntry? entry = null; 148 | 149 | foreach (var key in _lastEntityType.GetKeys()) 150 | { 151 | //TODO: Find faster way 152 | var keyArray = key.Properties.Where(p => p.PropertyInfo != null || p.FieldInfo != null).Select(p => 153 | p.PropertyInfo != null 154 | ? p.PropertyInfo.GetValue(args.Entity) 155 | : p.FieldInfo.GetValue(args.Entity)).ToArray(); 156 | 157 | if (keyArray.Length == key.Properties.Count) 158 | { 159 | entry = _stateManager.TryGetEntry(key, keyArray); 160 | 161 | if (entry != null) 162 | break; 163 | } 164 | } 165 | 166 | if (entry == null) 167 | { 168 | entry = _stateManager.StartTrackingFromQuery(_lastEntityType, args.Entity, ValueBuffer.Empty); 169 | } 170 | 171 | args.Entity = entry.Entity; 172 | } 173 | 174 | private void CopyDatabaseProperties() 175 | { 176 | var commandTimeout = Context?.Database.GetCommandTimeout(); 177 | if (commandTimeout != null) 178 | CommandTimeout = commandTimeout.Value; 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFToolsDataContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace LinqToDB.EntityFrameworkCore 8 | { 9 | 10 | using DataProvider; 11 | using Linq; 12 | 13 | /// 14 | /// linq2db EF.Core data context. 15 | /// 16 | public class LinqToDBForEFToolsDataContext : DataContext, IExpressionPreprocessor 17 | { 18 | readonly DbContext? _context; 19 | readonly IModel _model; 20 | readonly Func? _transformFunc; 21 | 22 | /// 23 | /// Creates instance of context. 24 | /// 25 | /// EF.Core database context. 26 | /// lin2db database provider instance. 27 | /// Connection string. 28 | /// EF.Core model. 29 | /// Expression converter. 30 | public LinqToDBForEFToolsDataContext( 31 | DbContext? context, 32 | IDataProvider dataProvider, 33 | string connectionString, 34 | IModel model, 35 | Func? transformFunc) : base(dataProvider, connectionString) 36 | { 37 | _context = context; 38 | _model = model; 39 | _transformFunc = transformFunc; 40 | } 41 | 42 | /// 43 | /// Converts expression using convert function, passed to context. 44 | /// 45 | /// Expression to convert. 46 | /// Converted expression. 47 | public Expression ProcessExpression(Expression expression) 48 | { 49 | if (_transformFunc == null) 50 | return expression; 51 | return _transformFunc(expression, this, _context, _model); 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFToolsException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToDB.EntityFrameworkCore 4 | { 5 | /// 6 | /// Exception class for EF.Core to LINQ To DB integration issues. 7 | /// 8 | public class LinqToDBForEFToolsException : Exception 9 | { 10 | /// 11 | /// Creates new instance of exception. 12 | /// 13 | public LinqToDBForEFToolsException() 14 | { 15 | } 16 | 17 | /// 18 | /// Creates new instance of exception. 19 | /// 20 | /// Exception message. 21 | public LinqToDBForEFToolsException(string message) : base(message) 22 | { 23 | } 24 | 25 | /// 26 | /// Creates new instance of exception when it generated for other exception. 27 | /// 28 | /// Exception message. 29 | /// Original exception. 30 | public LinqToDBForEFToolsException(string message, Exception innerException) : base(message, innerException) 31 | { 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/LinqToDBProviderInfo.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore 2 | { 3 | /// 4 | /// Stores LINQ To DB database provider information. 5 | /// 6 | public class LinqToDBProviderInfo 7 | { 8 | /// 9 | /// Server version. Currently is not used. 10 | /// 11 | public string? Version { get; set; } 12 | 13 | /// 14 | /// Gets or sets LINQ To DB provider name. 15 | /// for available providers. 16 | /// 17 | public string? ProviderName { get; set; } 18 | 19 | /// 20 | /// Replaces null values in current instance with values from parameter. 21 | /// 22 | /// Provider information to merge into current object. 23 | public void Merge(LinqToDBProviderInfo? providerInfo) 24 | { 25 | if (providerInfo != null) 26 | { 27 | Version = Version ?? providerInfo.Version; 28 | ProviderName = ProviderName ?? providerInfo.ProviderName; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/Properties/JetBrains.Annotations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | #pragma warning disable 1591 4 | // ReSharper disable UnusedMember.Global 5 | // ReSharper disable MemberCanBePrivate.Global 6 | // ReSharper disable UnusedAutoPropertyAccessor.Global 7 | // ReSharper disable IntroduceOptionalParameters.Global 8 | // ReSharper disable MemberCanBeProtected.Global 9 | // ReSharper disable InconsistentNaming 10 | 11 | namespace JetBrains.Annotations 12 | { 13 | /// 14 | /// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library), 15 | /// so this symbol will not be marked as unused (as well as by other usage inspections). 16 | /// 17 | [AttributeUsage(AttributeTargets.All)] 18 | internal sealed class UsedImplicitlyAttribute : Attribute 19 | { 20 | public UsedImplicitlyAttribute() 21 | : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) 22 | { 23 | } 24 | 25 | public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) 26 | : this(useKindFlags, ImplicitUseTargetFlags.Default) 27 | { 28 | } 29 | 30 | public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) 31 | : this(ImplicitUseKindFlags.Default, targetFlags) 32 | { 33 | } 34 | 35 | public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) 36 | { 37 | UseKindFlags = useKindFlags; 38 | TargetFlags = targetFlags; 39 | } 40 | 41 | public ImplicitUseKindFlags UseKindFlags { get; private set; } 42 | public ImplicitUseTargetFlags TargetFlags { get; private set; } 43 | } 44 | 45 | /// 46 | /// Should be used on attributes and causes ReSharper to not mark symbols marked with such attributes 47 | /// as unused (as well as by other usage inspections) 48 | /// 49 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter)] 50 | internal sealed class MeansImplicitUseAttribute : Attribute 51 | { 52 | public MeansImplicitUseAttribute() 53 | : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) 54 | { 55 | } 56 | 57 | public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) 58 | : this(useKindFlags, ImplicitUseTargetFlags.Default) 59 | { 60 | } 61 | 62 | public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) 63 | : this(ImplicitUseKindFlags.Default, targetFlags) 64 | { 65 | } 66 | 67 | public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) 68 | { 69 | UseKindFlags = useKindFlags; 70 | TargetFlags = targetFlags; 71 | } 72 | 73 | [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; } 74 | [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; } 75 | } 76 | 77 | [Flags] 78 | internal enum ImplicitUseKindFlags 79 | { 80 | Default = Access | Assign | InstantiatedWithFixedConstructorSignature, 81 | /// Only entity marked with attribute considered used. 82 | Access = 1, 83 | /// Indicates implicit assignment to a member. 84 | Assign = 2, 85 | /// 86 | /// Indicates implicit instantiation of a type with fixed constructor signature. 87 | /// That means any unused constructor parameters won't be reported as such. 88 | /// 89 | InstantiatedWithFixedConstructorSignature = 4, 90 | /// Indicates implicit instantiation of a type. 91 | InstantiatedNoFixedConstructorSignature = 8, 92 | } 93 | 94 | /// 95 | /// Specify what is considered used implicitly when marked 96 | /// with or . 97 | /// 98 | [Flags] 99 | internal enum ImplicitUseTargetFlags 100 | { 101 | Default = Itself, 102 | Itself = 1, 103 | /// Members of entity marked with attribute are considered used. 104 | Members = 2, 105 | /// Entity marked with attribute and all its members considered used. 106 | WithMembers = Itself | Members 107 | } 108 | 109 | /// 110 | /// This attribute is intended to mark publicly available API 111 | /// which should not be removed and so is treated as used. 112 | /// 113 | [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] 114 | [AttributeUsage(AttributeTargets.All)] 115 | internal sealed class PublicAPIAttribute : Attribute 116 | { 117 | public PublicAPIAttribute() 118 | { 119 | } 120 | 121 | public PublicAPIAttribute(string comment) 122 | { 123 | Comment = comment; 124 | } 125 | 126 | public string? Comment { get; private set; } 127 | } 128 | 129 | /// 130 | /// Indicates that a method does not make any observable state changes. 131 | /// The same as System.Diagnostics.Contracts.PureAttribute. 132 | /// 133 | /// 134 | /// [Pure] int Multiply(int x, int y) => x * y; 135 | /// 136 | /// void M() { 137 | /// Multiply(123, 42); // Waring: Return value of pure method is not used 138 | /// } 139 | /// 140 | [AttributeUsage(AttributeTargets.Method)] 141 | internal sealed class PureAttribute : Attribute 142 | { 143 | } 144 | 145 | /// 146 | /// Indicates that method is pure LINQ method, with postponed enumeration (like Enumerable.Select, 147 | /// .Where). This annotation allows inference of [InstantHandle] annotation for parameters 148 | /// of delegate type by analyzing LINQ method chains. 149 | /// 150 | [AttributeUsage(AttributeTargets.Method)] 151 | internal sealed class LinqTunnelAttribute : Attribute 152 | { 153 | } 154 | 155 | 156 | } 157 | -------------------------------------------------------------------------------- /Source/LinqToDB.EntityFrameworkCore/linq2db.EntityFrameworkCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Allows to execute Linq to DB (linq2db) queries in Entity Framework Core DbContext. 7 | Linq to DB (linq2db) extensions for Entity Framework Core 8 | $(Title) 9 | 10 | netstandard2.1 11 | LinqToDB.EntityFrameworkCore 12 | bin\$(Configuration)\$(TargetFramework)\linq2db.EntityFrameworkCore.xml 13 | 14 | 15 | EF1001 16 | latest 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/LinqToDB.EntityFrameworkCore.BaseTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Logging/LogMessageEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Logging 4 | { 5 | internal readonly struct LogMessageEntry 6 | { 7 | public LogMessageEntry(string message, string? timeStamp = null, string? levelString = null, ConsoleColor? levelBackground = null, ConsoleColor? levelForeground = null, ConsoleColor? messageColor = null, bool logAsError = false) 8 | { 9 | TimeStamp = timeStamp; 10 | LevelString = levelString; 11 | LevelBackground = levelBackground; 12 | LevelForeground = levelForeground; 13 | MessageColor = messageColor; 14 | Message = message; 15 | LogAsError = logAsError; 16 | } 17 | 18 | public readonly string? TimeStamp; 19 | public readonly string? LevelString; 20 | public readonly ConsoleColor? LevelBackground; 21 | public readonly ConsoleColor? LevelForeground; 22 | public readonly ConsoleColor? MessageColor; 23 | public readonly string Message; 24 | public readonly bool LogAsError; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Logging/NullExternalScopeProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Logging 5 | { 6 | /// 7 | /// Scope provider that does nothing. 8 | /// 9 | internal class NullExternalScopeProvider : IExternalScopeProvider 10 | { 11 | private NullExternalScopeProvider() 12 | { 13 | } 14 | 15 | /// 16 | /// Returns a cached instance of . 17 | /// 18 | public static IExternalScopeProvider Instance { get; } = new NullExternalScopeProvider(); 19 | 20 | /// 21 | void IExternalScopeProvider.ForEachScope(Action callback, TState state) 22 | { 23 | } 24 | 25 | /// 26 | IDisposable IExternalScopeProvider.Push(object state) 27 | { 28 | return NullScope.Instance; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Logging/NullScope.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Logging 4 | { 5 | internal class NullScope : IDisposable 6 | { 7 | public static NullScope Instance { get; } = new NullScope(); 8 | 9 | private NullScope() 10 | { 11 | } 12 | 13 | /// 14 | public void Dispose() 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Logging/TestLoggerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.DependencyInjection.Extensions; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.Extensions.Logging.Configuration; 6 | using Microsoft.Extensions.Logging.Console; 7 | 8 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Logging 9 | { 10 | public static class TestLoggerExtensions 11 | { 12 | /// 13 | /// Adds a console logger named 'Console' to the factory. 14 | /// 15 | /// The to use. 16 | public static ILoggingBuilder AddTestLogger(this ILoggingBuilder builder) 17 | { 18 | builder.AddConfiguration(); 19 | 20 | builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); 21 | LoggerProviderOptions.RegisterProviderOptions(builder.Services); 22 | return builder; 23 | } 24 | 25 | /// 26 | /// Adds a console logger named 'Console' to the factory. 27 | /// 28 | /// The to use. 29 | /// A delegate to configure the . 30 | public static ILoggingBuilder AddTestLogger(this ILoggingBuilder builder, Action configure) 31 | { 32 | if (configure == null) 33 | { 34 | throw new ArgumentNullException(nameof(configure)); 35 | } 36 | 37 | builder.AddTestLogger(); 38 | builder.Services.Configure(configure); 39 | 40 | return builder; 41 | } 42 | }} 43 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Logging/TestLoggerProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Logging.Console; 5 | using Microsoft.Extensions.Options; 6 | 7 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Logging 8 | { 9 | /// 10 | /// A provider of instances. 11 | /// 12 | [ProviderAlias("Console")] 13 | public class TestLoggerProvider : ILoggerProvider, ISupportExternalScope 14 | { 15 | private readonly IOptionsMonitor _options; 16 | private readonly ConcurrentDictionary _loggers; 17 | 18 | private readonly IDisposable _optionsReloadToken; 19 | private IExternalScopeProvider _scopeProvider = NullExternalScopeProvider.Instance; 20 | 21 | /// 22 | /// Creates an instance of . 23 | /// 24 | /// The options to create instances with. 25 | public TestLoggerProvider(IOptionsMonitor options) 26 | { 27 | _options = options; 28 | _loggers = new ConcurrentDictionary(); 29 | 30 | ReloadLoggerOptions(options.CurrentValue); 31 | _optionsReloadToken = _options.OnChange(ReloadLoggerOptions); 32 | } 33 | 34 | private void ReloadLoggerOptions(ConsoleLoggerOptions options) 35 | { 36 | foreach (var logger in _loggers) 37 | { 38 | logger.Value.Options = options; 39 | } 40 | } 41 | 42 | /// 43 | public ILogger CreateLogger(string categoryName) 44 | { 45 | return _loggers.GetOrAdd(categoryName, loggerName => new TestLogger(loggerName) 46 | { 47 | Options = _options.CurrentValue, 48 | ScopeProvider = _scopeProvider 49 | }); 50 | } 51 | 52 | /// 53 | public void Dispose() 54 | { 55 | _optionsReloadToken?.Dispose(); 56 | } 57 | 58 | /// 59 | public void SetScopeProvider(IExternalScopeProvider scopeProvider) 60 | { 61 | _scopeProvider = scopeProvider; 62 | 63 | foreach (var logger in _loggers) 64 | { 65 | logger.Value.ScopeProvider = _scopeProvider; 66 | } 67 | 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/BaseEntity.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 2 | { 3 | public class BaseEntity : ISoftDelete 4 | { 5 | public bool IsDeleted { get; set; } 6 | } 7 | 8 | public interface ISoftDelete 9 | { 10 | public bool IsDeleted { get; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Category.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public class Category : BaseEntity 6 | { 7 | public Category() 8 | { 9 | Products = new HashSet(); 10 | } 11 | 12 | public int CategoryId { get; set; } 13 | public string CategoryName { get; set; } = null!; 14 | public string? Description { get; set; } 15 | public byte[]? Picture { get; set; } 16 | 17 | public ICollection Products { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Customer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public class Customer : BaseEntity 6 | { 7 | public Customer() 8 | { 9 | CustomerCustomerDemo = new HashSet(); 10 | Orders = new HashSet(); 11 | } 12 | 13 | public string CustomerId { get; set; } = null!; 14 | public string CompanyName { get; set; } = null!; 15 | public string? ContactName { get; set; } 16 | public string? ContactTitle { get; set; } 17 | public string? Address { get; set; } 18 | public string? City { get; set; } 19 | public string? Region { get; set; } 20 | public string? PostalCode { get; set; } 21 | public string? Country { get; set; } 22 | public string? Phone { get; set; } 23 | public string? Fax { get; set; } 24 | 25 | public ICollection CustomerCustomerDemo { get; set; } 26 | public ICollection Orders { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/CustomerCustomerDemo.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 2 | { 3 | public class CustomerCustomerDemo : BaseEntity 4 | { 5 | public string CustomerId { get; set; } = null!; 6 | public string CustomerTypeId { get; set; } = null!; 7 | 8 | public Customer Customer { get; set; } = null!; 9 | public CustomerDemographics CustomerType { get; set; } = null!; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/CustomerDemographics.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public class CustomerDemographics : BaseEntity 6 | { 7 | public CustomerDemographics() 8 | { 9 | CustomerCustomerDemo = new HashSet(); 10 | } 11 | 12 | public string CustomerTypeId { get; set; } = null!; 13 | public string? CustomerDesc { get; set; } 14 | 15 | public ICollection CustomerCustomerDemo { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/CustomerOrderHistory.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 3 | { 4 | public class CustomerOrderHistory : BaseEntity 5 | { 6 | public string ProductName { get; set; } = null!; 7 | 8 | public int Total { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/CustomerQuery.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 5 | { 6 | public class CustomerQuery : BaseEntity 7 | { 8 | public string CompanyName { get; set; } = null!; 9 | public int OrderCount { get; set; } 10 | public string SearchTerm { get; set; } = null!; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/CustomerView.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 | 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | 6 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 7 | { 8 | public class CustomerView : BaseEntity 9 | { 10 | public string? CompanyName { get; set; } 11 | public string? ContactName { get; set; } 12 | public string? ContactTitle { get; set; } 13 | public string? Address { get; set; } 14 | public string? City { get; set; } 15 | 16 | [NotMapped] 17 | public bool IsLondon => City == "London"; 18 | 19 | protected bool Equals(CustomerView other) 20 | => string.Equals(CompanyName, other.CompanyName); 21 | 22 | public override bool Equals(object? obj) 23 | { 24 | if (obj is null) 25 | { 26 | return false; 27 | } 28 | 29 | return ReferenceEquals(this, obj) 30 | ? true 31 | : obj.GetType() == GetType() 32 | && Equals((CustomerView)obj); 33 | } 34 | 35 | public static bool operator ==(CustomerView left, CustomerView right) 36 | => Equals(left, right); 37 | 38 | public static bool operator !=(CustomerView left, CustomerView right) 39 | => !Equals(left, right); 40 | 41 | public override int GetHashCode() 42 | // ReSharper disable once NonReadonlyMemberInGetHashCode 43 | => CompanyName?.GetHashCode() ?? 0; 44 | 45 | public override string ToString() 46 | => "CustomerView " + CompanyName; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Employee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 5 | { 6 | public class Employee : BaseEntity 7 | { 8 | public Employee() 9 | { 10 | EmployeeTerritories = new HashSet(); 11 | InverseReportsToNavigation = new HashSet(); 12 | Orders = new HashSet(); 13 | } 14 | 15 | public int EmployeeId { get; set; } 16 | public string LastName { get; set; } = null!; 17 | public string FirstName { get; set; } = null!; 18 | public string? Title { get; set; } 19 | public string? TitleOfCourtesy { get; set; } 20 | public DateTime? BirthDate { get; set; } 21 | public DateTime? HireDate { get; set; } 22 | public string? Address { get; set; } 23 | public string? City { get; set; } 24 | public string? Region { get; set; } 25 | public string? PostalCode { get; set; } 26 | public string? Country { get; set; } 27 | public string? HomePhone { get; set; } 28 | public string? Extension { get; set; } 29 | public byte[]? Photo { get; set; } 30 | public string? Notes { get; set; } 31 | public int? ReportsTo { get; set; } 32 | public string? PhotoPath { get; set; } 33 | 34 | public Employee? ReportsToNavigation { get; set; } 35 | public ICollection EmployeeTerritories { get; set; } 36 | public ICollection InverseReportsToNavigation { get; set; } 37 | public ICollection Orders { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/EmployeeTerritory.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 2 | { 3 | public class EmployeeTerritory : BaseEntity 4 | { 5 | public int EmployeeId { get; set; } 6 | public string TerritoryId { get; set; } = null!; 7 | 8 | public Employee Employee { get; set; } = null!; 9 | public Territory Territory { get; set; } = null!; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 5 | { 6 | public class Order : BaseEntity 7 | { 8 | public Order() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int OrderId { get; set; } 14 | public string? CustomerId { get; set; } 15 | public int? EmployeeId { get; set; } 16 | public DateTime? OrderDate { get; set; } 17 | public DateTime? RequiredDate { get; set; } 18 | public DateTime? ShippedDate { get; set; } 19 | public int? ShipVia { get; set; } 20 | public decimal? Freight { get; set; } 21 | public string? ShipName { get; set; } 22 | public string? ShipAddress { get; set; } 23 | public string? ShipCity { get; set; } 24 | public string? ShipRegion { get; set; } 25 | public string? ShipPostalCode { get; set; } 26 | public string? ShipCountry { get; set; } 27 | 28 | public Customer? Customer { get; set; } 29 | public Employee? Employee { get; set; } 30 | public Shipper? ShipViaNavigation { get; set; } 31 | public ICollection OrderDetails { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/OrderDetail.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 2 | { 3 | public class OrderDetail : BaseEntity 4 | { 5 | public int OrderId { get; set; } 6 | public int ProductId { get; set; } 7 | public decimal UnitPrice { get; set; } 8 | public short Quantity { get; set; } 9 | public float Discount { get; set; } 10 | 11 | public Order Order { get; set; } = null!; 12 | public Product Product { get; set; } = null!; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Product.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public class Product : BaseEntity 6 | { 7 | public Product() 8 | { 9 | OrderDetails = new HashSet(); 10 | } 11 | 12 | public int ProductId { get; set; } 13 | public string ProductName { get; set; } = null!; 14 | public int? SupplierId { get; set; } 15 | public int? CategoryId { get; set; } 16 | public string? QuantityPerUnit { get; set; } 17 | public decimal? UnitPrice { get; set; } 18 | public short? UnitsInStock { get; set; } 19 | public short? UnitsOnOrder { get; set; } 20 | public short? ReorderLevel { get; set; } 21 | public bool Discontinued { get; set; } 22 | 23 | public Category? Category { get; set; } 24 | public Supplier? Supplier { get; set; } 25 | public ICollection OrderDetails { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Region.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public partial class Region : BaseEntity 6 | { 7 | public Region() 8 | { 9 | Territories = new HashSet(); 10 | } 11 | 12 | public int RegionId { get; set; } 13 | public string RegionDescription { get; set; } = null!; 14 | 15 | public ICollection Territories { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Shipper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public class Shipper : BaseEntity 6 | { 7 | public Shipper() 8 | { 9 | Orders = new HashSet(); 10 | } 11 | 12 | public int ShipperId { get; set; } 13 | public string CompanyName { get; set; } = null!; 14 | public string? Phone { get; set; } 15 | 16 | public ICollection Orders { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Supplier.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public class Supplier : BaseEntity 6 | { 7 | public Supplier() 8 | { 9 | Products = new HashSet(); 10 | } 11 | 12 | public int SupplierId { get; set; } 13 | public string CompanyName { get; set; } = null!; 14 | public string? ContactName { get; set; } 15 | public string? ContactTitle { get; set; } 16 | public string? Address { get; set; } 17 | public string? City { get; set; } 18 | public string? Region { get; set; } 19 | public string? PostalCode { get; set; } 20 | public string? Country { get; set; } 21 | public string? Phone { get; set; } 22 | public string? Fax { get; set; } 23 | public string? HomePage { get; set; } 24 | 25 | public ICollection Products { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/Models/Northwind/Territory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind 4 | { 5 | public class Territory : BaseEntity 6 | { 7 | public Territory() 8 | { 9 | EmployeeTerritories = new HashSet(); 10 | } 11 | 12 | public string TerritoryId { get; set; } = null!; 13 | public string TerritoryDescription { get; set; } = null!; 14 | public int RegionId { get; set; } 15 | 16 | public Region Region { get; set; } = null!; 17 | public ICollection EmployeeTerritories { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/TestUtils.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Logging; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Logging.Console; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.BaseTests 6 | { 7 | public class TestUtils 8 | { 9 | public static readonly ILoggerFactory LoggerFactory = 10 | Microsoft.Extensions.Logging.LoggerFactory.Create(builder => 11 | { 12 | builder.AddFilter("Microsoft", LogLevel.Information) 13 | .AddFilter("System", LogLevel.Warning) 14 | .AddFilter("LinqToDB.EntityFrameworkCore.Test", LogLevel.Information) 15 | 16 | .AddTestLogger(o => 17 | { 18 | o.IncludeScopes = true; 19 | o.FormatterName = ConsoleFormatterNames.Simple; 20 | }); 21 | }); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.BaseTests/TestsBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using LinqToDB.Reflection; 7 | using LinqToDB.Tools; 8 | using LinqToDB.Tools.Comparers; 9 | using NUnit.Framework; 10 | 11 | namespace LinqToDB.EntityFrameworkCore.BaseTests 12 | { 13 | public class TestsBase 14 | { 15 | protected void AreEqual(IEnumerable expected, IEnumerable result, bool allowEmpty = false) 16 | { 17 | AreEqual(t => t, expected, result, EqualityComparer.Default, allowEmpty); 18 | } 19 | 20 | protected void AreEqual(IEnumerable expected, IEnumerable result, Func, IEnumerable> sort) 21 | { 22 | AreEqual(t => t, expected, result, EqualityComparer.Default, sort); 23 | } 24 | 25 | protected void AreEqualWithComparer(IEnumerable expected, IEnumerable result) 26 | { 27 | AreEqual(t => t, expected, result, ComparerBuilder.GetEqualityComparer()); 28 | } 29 | 30 | protected void AreEqualWithComparer(IEnumerable expected, IEnumerable result, Func memberPredicate) 31 | { 32 | AreEqual(t => t, expected, result, ComparerBuilder.GetEqualityComparer(memberPredicate)); 33 | } 34 | 35 | protected void AreEqual(IEnumerable expected, IEnumerable result, IEqualityComparer comparer) 36 | { 37 | AreEqual(t => t, expected, result, comparer); 38 | } 39 | 40 | protected void AreEqual(IEnumerable expected, IEnumerable result, IEqualityComparer comparer, Func, IEnumerable> sort) 41 | { 42 | AreEqual(t => t, expected, result, comparer, sort); 43 | } 44 | 45 | protected void AreEqual(Func fixSelector, IEnumerable expected, IEnumerable result) 46 | { 47 | AreEqual(fixSelector, expected, result, EqualityComparer.Default); 48 | } 49 | 50 | protected void AreEqual(Func fixSelector, IEnumerable expected, IEnumerable result, IEqualityComparer comparer, bool allowEmpty = false) 51 | { 52 | AreEqual(fixSelector, expected, result, comparer, null, allowEmpty); 53 | } 54 | 55 | protected void AreEqual( 56 | Func fixSelector, 57 | IEnumerable expected, 58 | IEnumerable result, 59 | IEqualityComparer comparer, 60 | Func, IEnumerable>? sort, 61 | bool allowEmpty = false) 62 | { 63 | var resultList = result.Select(fixSelector).ToList(); 64 | var expectedList = expected.Select(fixSelector).ToList(); 65 | 66 | if (sort != null) 67 | { 68 | resultList = sort(resultList).ToList(); 69 | expectedList = sort(expectedList).ToList(); 70 | } 71 | 72 | if (!allowEmpty) 73 | Assert.AreNotEqual(0, expectedList.Count, "Expected list cannot be empty."); 74 | Assert.AreEqual(expectedList.Count, resultList.Count, "Expected and result lists are different. Length: "); 75 | 76 | var exceptExpectedList = resultList.Except(expectedList, comparer).ToList(); 77 | var exceptResultList = expectedList.Except(resultList, comparer).ToList(); 78 | 79 | var exceptExpected = exceptExpectedList.Count; 80 | var exceptResult = exceptResultList.Count; 81 | var message = new StringBuilder(); 82 | 83 | if (exceptResult != 0 || exceptExpected != 0) 84 | { 85 | Debug.WriteLine(resultList.ToDiagnosticString()); 86 | Debug.WriteLine(expectedList.ToDiagnosticString()); 87 | 88 | for (var i = 0; i < resultList.Count; i++) 89 | { 90 | Debug.WriteLine("{0} {1} --- {2}", comparer.Equals(expectedList[i], resultList[i]) ? " " : "-", expectedList[i], resultList[i]); 91 | message.AppendFormat("{0} {1} --- {2}", comparer.Equals(expectedList[i], resultList[i]) ? " " : "-", expectedList[i], resultList[i]); 92 | message.AppendLine(); 93 | } 94 | } 95 | 96 | Assert.AreEqual(0, exceptExpected, $"Expected Was{Environment.NewLine}{message}"); 97 | Assert.AreEqual(0, exceptResult, $"Expect Result{Environment.NewLine}{message}"); 98 | } 99 | 100 | protected void AreEqual(IEnumerable> expected, IEnumerable> result) 101 | { 102 | var resultList = result.ToList(); 103 | var expectedList = expected.ToList(); 104 | 105 | Assert.AreNotEqual(0, expectedList.Count); 106 | Assert.AreEqual(expectedList.Count, resultList.Count, "Expected and result lists are different. Length: "); 107 | 108 | for (var i = 0; i < resultList.Count; i++) 109 | { 110 | var elist = expectedList[i].ToList(); 111 | var rlist = resultList[i].ToList(); 112 | 113 | if (elist.Count > 0 || rlist.Count > 0) 114 | AreEqual(elist, rlist); 115 | } 116 | } 117 | 118 | protected void AreSame(IEnumerable expected, IEnumerable result) 119 | { 120 | var resultList = result.ToList(); 121 | var expectedList = expected.ToList(); 122 | 123 | Assert.AreNotEqual(0, expectedList.Count); 124 | Assert.AreEqual(expectedList.Count, resultList.Count); 125 | 126 | var b = expectedList.SequenceEqual(resultList); 127 | 128 | if (!b) 129 | for (var i = 0; i < resultList.Count; i++) 130 | Debug.WriteLine("{0} {1} --- {2}", Equals(expectedList[i], resultList[i]) ? " " : "-", expectedList[i], resultList[i]); 131 | 132 | Assert.IsTrue(b); 133 | } 134 | 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/CategoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CategoriesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.CategoryId); 13 | 14 | builder.HasIndex(e => e.CategoryName) 15 | .HasDatabaseName("CategoryName"); 16 | 17 | builder.Property(e => e.CategoryId).HasColumnName("CategoryID") 18 | .ValueGeneratedNever(); 19 | 20 | builder.Property(e => e.CategoryName) 21 | .IsRequired() 22 | .HasMaxLength(15); 23 | 24 | builder.Property(e => e.Description).HasColumnType("text"); 25 | 26 | builder.Property(e => e.Picture).HasColumnType("blob"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/CustomerCustomerDemoMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomerCustomerDemoMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => new { e.CustomerId, e.CustomerTypeId }); 13 | 14 | builder.Property(e => e.CustomerId) 15 | .HasColumnName("CustomerID") 16 | .HasMaxLength(5); 17 | 18 | builder.Property(e => e.CustomerTypeId) 19 | .HasColumnName("CustomerTypeID") 20 | .HasMaxLength(10); 21 | 22 | builder.HasOne(d => d.Customer) 23 | .WithMany(p => p.CustomerCustomerDemo) 24 | .HasForeignKey(d => d.CustomerId) 25 | .OnDelete(DeleteBehavior.ClientSetNull) 26 | .HasConstraintName("FK_CustomerCustomerDemo_Customers"); 27 | 28 | builder.HasOne(d => d.CustomerType) 29 | .WithMany(p => p.CustomerCustomerDemo) 30 | .HasForeignKey(d => d.CustomerTypeId) 31 | .OnDelete(DeleteBehavior.ClientSetNull) 32 | .HasConstraintName("FK_CustomerCustomerDemo"); 33 | 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/CustomerDemographicsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomerDemographicsMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.CustomerTypeId); 12 | 13 | builder.Property(e => e.CustomerTypeId) 14 | .HasColumnName("CustomerTypeID") 15 | .HasMaxLength(10) 16 | .ValueGeneratedNever(); 17 | 18 | builder.Property(e => e.CustomerDesc).HasColumnType("text"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/CustomersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomersMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.CustomerId); 13 | 14 | builder.HasIndex(e => e.City) 15 | .HasDatabaseName("City"); 16 | 17 | builder.HasIndex(e => e.CompanyName) 18 | .HasDatabaseName("CompanyName"); 19 | 20 | builder.HasIndex(e => e.PostalCode) 21 | .HasDatabaseName("PostalCode"); 22 | 23 | builder.HasIndex(e => e.Region) 24 | .HasDatabaseName("Region"); 25 | 26 | builder.Property(e => e.CustomerId) 27 | .HasColumnName("CustomerID") 28 | .HasMaxLength(5) 29 | .ValueGeneratedNever(); 30 | 31 | builder.Property(e => e.Address).HasMaxLength(60); 32 | builder.Property(e => e.City).HasMaxLength(15); 33 | builder.Property(e => e.CompanyName) 34 | .IsRequired() 35 | .HasMaxLength(40); 36 | 37 | builder.Property(e => e.ContactName).HasMaxLength(30); 38 | builder.Property(e => e.ContactTitle).HasMaxLength(30); 39 | builder.Property(e => e.Country).HasMaxLength(15); 40 | builder.Property(e => e.Fax).HasMaxLength(24); 41 | builder.Property(e => e.Phone).HasMaxLength(24); 42 | builder.Property(e => e.PostalCode).HasMaxLength(10); 43 | builder.Property(e => e.Region).HasMaxLength(15); 44 | 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/EmployeeTerritoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class EmployeeTerritoriesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => new { e.EmployeeId, e.TerritoryId }); 12 | 13 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID"); 14 | 15 | builder.Property(e => e.TerritoryId) 16 | .HasColumnName("TerritoryID") 17 | .HasMaxLength(20); 18 | 19 | builder.HasOne(d => d.Employee) 20 | .WithMany(p => p.EmployeeTerritories) 21 | .HasForeignKey(d => d.EmployeeId) 22 | .OnDelete(DeleteBehavior.ClientSetNull) 23 | .HasConstraintName("FK_EmployeeTerritories_Employees"); 24 | 25 | builder.HasOne(d => d.Territory) 26 | .WithMany(p => p.EmployeeTerritories) 27 | .HasForeignKey(d => d.TerritoryId) 28 | .OnDelete(DeleteBehavior.ClientSetNull) 29 | .HasConstraintName("FK_EmployeeTerritories_Territories"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/EmployeesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class EmployeesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.EmployeeId); 12 | 13 | builder.HasIndex(e => e.LastName) 14 | .HasDatabaseName("LastName"); 15 | 16 | builder.HasIndex(e => e.PostalCode) 17 | .HasDatabaseName("PostalCode"); 18 | 19 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID") 20 | .ValueGeneratedNever(); 21 | 22 | builder.Property(e => e.Address).HasMaxLength(60); 23 | 24 | builder.Property(e => e.BirthDate).HasColumnType("datetime"); 25 | 26 | builder.Property(e => e.City).HasMaxLength(15); 27 | 28 | builder.Property(e => e.Country).HasMaxLength(15); 29 | 30 | builder.Property(e => e.Extension).HasMaxLength(4); 31 | 32 | builder.Property(e => e.FirstName) 33 | .IsRequired() 34 | .HasMaxLength(10); 35 | 36 | builder.Property(e => e.HireDate).HasColumnType("datetime"); 37 | 38 | builder.Property(e => e.HomePhone).HasMaxLength(24); 39 | 40 | builder.Property(e => e.LastName) 41 | .IsRequired() 42 | .HasMaxLength(20); 43 | 44 | builder.Property(e => e.Notes).HasColumnType("text"); 45 | 46 | builder.Property(e => e.Photo).HasColumnType("blob"); 47 | 48 | builder.Property(e => e.PhotoPath).HasMaxLength(255); 49 | 50 | builder.Property(e => e.PostalCode).HasMaxLength(10); 51 | 52 | builder.Property(e => e.Region).HasMaxLength(15); 53 | 54 | builder.Property(e => e.Title).HasMaxLength(30); 55 | 56 | builder.Property(e => e.TitleOfCourtesy).HasMaxLength(25); 57 | 58 | builder.HasOne(d => d.ReportsToNavigation) 59 | .WithMany(p => p!.InverseReportsToNavigation) 60 | .HasForeignKey(d => d.ReportsTo) 61 | .HasConstraintName("FK_Employees_Employees"); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/OrderDetailsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class OrderDetailsMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => new { e.OrderId, e.ProductId }); 12 | 13 | builder.ToTable("Order Details"); 14 | 15 | builder.HasIndex(e => e.OrderId) 16 | .HasDatabaseName("OrdersOrder_Details"); 17 | 18 | builder.HasIndex(e => e.ProductId) 19 | .HasDatabaseName("ProductsOrder_Details"); 20 | 21 | builder.Property(e => e.OrderId).HasColumnName("OrderID"); 22 | 23 | builder.Property(e => e.ProductId).HasColumnName("ProductID"); 24 | 25 | builder.Property(e => e.Quantity).HasDefaultValue(1); 26 | 27 | builder.Property(e => e.UnitPrice).HasColumnType("decimal(13, 4)"); 28 | 29 | builder.HasOne(d => d.Order) 30 | .WithMany(p => p.OrderDetails) 31 | .HasForeignKey(d => d.OrderId) 32 | .OnDelete(DeleteBehavior.ClientSetNull) 33 | .HasConstraintName("FK_Order_Details_Orders"); 34 | 35 | builder.HasOne(d => d.Product) 36 | .WithMany(p => p.OrderDetails) 37 | .HasForeignKey(d => d.ProductId) 38 | .OnDelete(DeleteBehavior.ClientSetNull) 39 | .HasConstraintName("FK_Order_Details_Products"); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/OrderMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class OrderMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.OrderId); 13 | 14 | builder.HasIndex(e => e.CustomerId) 15 | .HasDatabaseName("CustomersOrders"); 16 | 17 | builder.HasIndex(e => e.EmployeeId) 18 | .HasDatabaseName("EmployeesOrders"); 19 | 20 | builder.HasIndex(e => e.OrderDate) 21 | .HasDatabaseName("OrderDate"); 22 | 23 | builder.HasIndex(e => e.ShipPostalCode) 24 | .HasDatabaseName("ShipPostalCode"); 25 | 26 | builder.HasIndex(e => e.ShipVia) 27 | .HasDatabaseName("ShippersOrders"); 28 | 29 | builder.HasIndex(e => e.ShippedDate) 30 | .HasDatabaseName("ShippedDate"); 31 | 32 | builder.Property(e => e.OrderId).HasColumnName("OrderID") 33 | .ValueGeneratedNever(); 34 | 35 | builder.Property(e => e.CustomerId) 36 | .HasColumnName("CustomerID") 37 | .HasMaxLength(5); 38 | 39 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID"); 40 | 41 | builder.Property(e => e.Freight) 42 | .HasColumnType("decimal(13, 4)") 43 | .HasDefaultValue(0m); 44 | 45 | builder.Property(e => e.OrderDate).HasColumnType("datetime"); 46 | 47 | builder.Property(e => e.RequiredDate).HasColumnType("datetime"); 48 | 49 | builder.Property(e => e.ShipAddress).HasMaxLength(60); 50 | 51 | builder.Property(e => e.ShipCity).HasMaxLength(15); 52 | 53 | builder.Property(e => e.ShipCountry).HasMaxLength(15); 54 | 55 | builder.Property(e => e.ShipName).HasMaxLength(40); 56 | 57 | builder.Property(e => e.ShipPostalCode).HasMaxLength(10); 58 | 59 | builder.Property(e => e.ShipRegion).HasMaxLength(15); 60 | 61 | builder.Property(e => e.ShippedDate).HasColumnType("datetime"); 62 | 63 | builder.HasOne(d => d.Customer) 64 | .WithMany(p => p!.Orders) 65 | .HasForeignKey(d => d.CustomerId) 66 | .HasConstraintName("FK_Orders_Customers"); 67 | 68 | builder.HasOne(d => d.Employee) 69 | .WithMany(p => p!.Orders) 70 | .HasForeignKey(d => d.EmployeeId) 71 | .HasConstraintName("FK_Orders_Employees"); 72 | 73 | builder.HasOne(d => d.ShipViaNavigation) 74 | .WithMany(p => p!.Orders) 75 | .HasForeignKey(d => d.ShipVia) 76 | .HasConstraintName("FK_Orders_Shippers"); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/ProductsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class ProductsMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.ProductId); 12 | 13 | builder.HasIndex(e => e.CategoryId) 14 | .HasDatabaseName("CategoryID"); 15 | 16 | builder.HasIndex(e => e.ProductName) 17 | .HasDatabaseName("ProductName"); 18 | 19 | builder.HasIndex(e => e.SupplierId) 20 | .HasDatabaseName("SuppliersProducts"); 21 | 22 | builder.Property(e => e.ProductId).HasColumnName("ProductID") 23 | .ValueGeneratedNever(); 24 | 25 | builder.Property(e => e.CategoryId).HasColumnName("CategoryID"); 26 | 27 | builder.Property(e => e.ProductName) 28 | .IsRequired() 29 | .HasMaxLength(40); 30 | 31 | builder.Property(e => e.QuantityPerUnit).HasMaxLength(20); 32 | 33 | builder.Property(e => e.ReorderLevel).HasDefaultValue((short)0); 34 | 35 | builder.Property(e => e.SupplierId).HasColumnName("SupplierID"); 36 | 37 | builder.Property(e => e.UnitPrice) 38 | .HasColumnType("decimal(13, 4)") 39 | .HasDefaultValue(0m); 40 | 41 | builder.Property(e => e.UnitsInStock).HasDefaultValue((short)0); 42 | 43 | builder.Property(e => e.UnitsOnOrder).HasDefaultValue((short)0); 44 | 45 | builder.HasOne(d => d.Category) 46 | .WithMany(p => p!.Products) 47 | .HasForeignKey(d => d.CategoryId) 48 | .HasConstraintName("FK_Products_Categories"); 49 | 50 | builder.HasOne(d => d.Supplier) 51 | .WithMany(p => p!.Products) 52 | .HasForeignKey(d => d.SupplierId) 53 | .HasConstraintName("FK_Products_Suppliers"); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/RegionMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class RegionMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.RegionId); 12 | 13 | builder.Property(e => e.RegionId) 14 | .HasColumnName("RegionID") 15 | .ValueGeneratedNever(); 16 | 17 | builder.Property(e => e.RegionDescription) 18 | .IsRequired() 19 | .HasMaxLength(50); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/ShippersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class ShippersMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.ShipperId); 12 | 13 | builder.Property(e => e.ShipperId).HasColumnName("ShipperID") 14 | .ValueGeneratedNever(); 15 | 16 | builder.Property(e => e.CompanyName) 17 | .IsRequired() 18 | .HasMaxLength(40); 19 | 20 | builder.Property(e => e.Phone).HasMaxLength(24); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/SuppliersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class SuppliersMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.SupplierId); 13 | 14 | builder.HasIndex(e => e.CompanyName) 15 | .HasDatabaseName("CompanyName"); 16 | 17 | builder.HasIndex(e => e.PostalCode) 18 | .HasDatabaseName("PostalCode"); 19 | 20 | builder.Property(e => e.SupplierId).HasColumnName("SupplierID") 21 | .ValueGeneratedNever(); 22 | 23 | builder.Property(e => e.Address).HasMaxLength(60); 24 | 25 | builder.Property(e => e.City).HasMaxLength(15); 26 | 27 | builder.Property(e => e.CompanyName) 28 | .IsRequired() 29 | .HasMaxLength(40); 30 | 31 | builder.Property(e => e.ContactName).HasMaxLength(30); 32 | 33 | builder.Property(e => e.ContactTitle).HasMaxLength(30); 34 | 35 | builder.Property(e => e.Country).HasMaxLength(15); 36 | 37 | builder.Property(e => e.Fax).HasMaxLength(24); 38 | 39 | builder.Property(e => e.HomePage).HasColumnType("text"); 40 | 41 | builder.Property(e => e.Phone).HasMaxLength(24); 42 | 43 | builder.Property(e => e.PostalCode).HasMaxLength(10); 44 | 45 | builder.Property(e => e.Region).HasMaxLength(15); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind.Mapping/TerritoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class TerritoriesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.TerritoryId); 12 | 13 | builder.Property(e => e.TerritoryId) 14 | .HasColumnName("TerritoryID") 15 | .HasMaxLength(20) 16 | .ValueGeneratedNever(); 17 | 18 | builder.Property(e => e.RegionId).HasColumnName("RegionID"); 19 | 20 | builder.Property(e => e.TerritoryDescription) 21 | .IsRequired() 22 | .HasMaxLength(50); 23 | 24 | builder.HasOne(d => d.Region) 25 | .WithMany(p => p.Territories) 26 | .HasForeignKey(d => d.RegionId) 27 | .OnDelete(DeleteBehavior.ClientSetNull) 28 | .HasConstraintName("FK_Territories_Region"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/Models/Northwind/NorthwindContext.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind 6 | { 7 | public class NorthwindContext : DbContext 8 | { 9 | public DbSet Categories { get; set; } = null!; 10 | public DbSet CustomerCustomerDemo { get; set; } = null!; 11 | public DbSet CustomerDemographics { get; set; } = null!; 12 | public DbSet Customers { get; set; } = null!; 13 | public DbSet Employees { get; set; } = null!; 14 | public DbSet EmployeeTerritories { get; set; } = null!; 15 | public DbSet OrderDetails { get; set; } = null!; 16 | public DbSet Orders { get; set; } = null!; 17 | public DbSet Products { get; set; } = null!; 18 | public DbSet Region { get; set; } = null!; 19 | public DbSet Shippers { get; set; } = null!; 20 | public DbSet Suppliers { get; set; } = null!; 21 | public DbSet Territories { get; set; } = null!; 22 | 23 | public NorthwindContext(DbContextOptions options) : base(options) 24 | { 25 | 26 | } 27 | 28 | protected override void OnModelCreating(ModelBuilder modelBuilder) 29 | { 30 | modelBuilder.ApplyConfiguration(new CategoriesMap()); 31 | modelBuilder.ApplyConfiguration(new CustomerCustomerDemoMap()); 32 | modelBuilder.ApplyConfiguration(new CustomerDemographicsMap()); 33 | modelBuilder.ApplyConfiguration(new CustomersMap()); 34 | modelBuilder.ApplyConfiguration(new EmployeesMap()); 35 | modelBuilder.ApplyConfiguration(new EmployeeTerritoriesMap()); 36 | modelBuilder.ApplyConfiguration(new OrderDetailsMap()); 37 | modelBuilder.ApplyConfiguration(new OrderMap()); 38 | modelBuilder.ApplyConfiguration(new ProductsMap()); 39 | modelBuilder.ApplyConfiguration(new RegionMap()); 40 | modelBuilder.ApplyConfiguration(new ShippersMap()); 41 | modelBuilder.ApplyConfiguration(new SuppliersMap()); 42 | modelBuilder.ApplyConfiguration(new TerritoriesMap()); 43 | 44 | modelBuilder.Entity() 45 | .HasQueryFilter(e => !IsFilterProducts || e.ProductId > 2); 46 | } 47 | 48 | public bool IsFilterProducts { get; set; } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PomeloMySql.Tests/PomeloMySqlTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using LinqToDB.Data; 4 | using LinqToDB.EntityFrameworkCore.BaseTests; 5 | using LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind; 6 | using Microsoft.EntityFrameworkCore; 7 | using NUnit.Framework; 8 | using Pomelo.EntityFrameworkCore.MySql.Infrastructure; 9 | using Pomelo.EntityFrameworkCore.MySql.Storage; 10 | 11 | namespace LinqToDB.EntityFrameworkCore.PomeloMySql.Tests 12 | { 13 | public class PomeloMySqlTests : TestsBase 14 | { 15 | private DbContextOptions _options; 16 | 17 | static PomeloMySqlTests() 18 | { 19 | LinqToDBForEFTools.Initialize(); 20 | DataConnection.TurnTraceSwitchOn(); 21 | } 22 | 23 | public PomeloMySqlTests() 24 | { 25 | var optionsBuilder = new DbContextOptionsBuilder(); 26 | //new SqlServerDbContextOptionsBuilder(optionsBuilder); 27 | 28 | optionsBuilder.UseMySql( 29 | "Server=DBHost;Port=3306;Database=TestData;Uid=TestUser;Pwd=TestPassword;charset=utf8;", 30 | builder => builder.ServerVersion(ServerVersion.Default)); 31 | 32 | optionsBuilder.UseLoggerFactory(TestUtils.LoggerFactory); 33 | 34 | _options = optionsBuilder.Options; 35 | } 36 | 37 | private NorthwindContext CreateMySqlSqlExntitiesContext() 38 | { 39 | var ctx = new NorthwindContext(_options); 40 | ctx.Database.EnsureDeleted(); 41 | ctx.Database.EnsureCreated(); 42 | return ctx; 43 | } 44 | 45 | 46 | [Test] 47 | public void SimpleProviderTest() 48 | { 49 | using (var db = CreateMySqlSqlExntitiesContext()) 50 | { 51 | var items = db.Customers.Where(e => e.Address != null).ToLinqToDB().ToArray(); 52 | } 53 | } 54 | 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/Models/NpgSqlEntities/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NpgsqlTypes; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.Models.NpgSqlEntities 5 | { 6 | public class Event 7 | { 8 | public int Id { get; set; } 9 | public string Name { get; set; } = null!; 10 | public NpgsqlRange Duration { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/Models/NpgSqlEntities/EventView.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.Models.NpgSqlEntities 2 | { 3 | public class EventView 4 | { 5 | public string Name { get; set; } = null!; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/Models/NpgSqlEntities/NpgSqlEnititesContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.Models.NpgSqlEntities 4 | { 5 | public class NpgSqlEnititesContext : DbContext 6 | { 7 | public NpgSqlEnititesContext(DbContextOptions options) 8 | : base(options) 9 | { 10 | } 11 | 12 | protected override void OnModelCreating(ModelBuilder modelBuilder) 13 | { 14 | modelBuilder.Entity(entity => 15 | entity.Property(e => e.Duration).HasColumnType("tsrange") 16 | ); 17 | 18 | modelBuilder.Entity(entity => 19 | { 20 | entity.HasNoKey(); 21 | entity.ToView("EventsView", "views"); 22 | }); 23 | } 24 | 25 | public virtual DbSet Events { get; set; } = null!; 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/NpgSqlTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using LinqToDB.Data; 4 | using LinqToDB.EntityFrameworkCore.BaseTests; 5 | using LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.Models.NpgSqlEntities; 6 | using Microsoft.EntityFrameworkCore; 7 | using NUnit.Framework; 8 | 9 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests 10 | { 11 | public class NpgSqlTests : TestsBase 12 | { 13 | private DbContextOptions _options; 14 | 15 | static NpgSqlTests() 16 | { 17 | LinqToDBForEFTools.Initialize(); 18 | DataConnection.TurnTraceSwitchOn(); 19 | } 20 | 21 | public NpgSqlTests() 22 | { 23 | var optionsBuilder = new DbContextOptionsBuilder(); 24 | //new SqlServerDbContextOptionsBuilder(optionsBuilder); 25 | 26 | optionsBuilder.UseNpgsql("Server=DBHost;Port=5432;Database=TestData;User Id=postgres;Password=TestPassword;Pooling=true;MinPoolSize=10;MaxPoolSize=100;"); 27 | optionsBuilder.UseLoggerFactory(TestUtils.LoggerFactory); 28 | 29 | _options = optionsBuilder.Options; 30 | } 31 | 32 | private NpgSqlEnititesContext CreateNpgSqlEntitiesContext() 33 | { 34 | var ctx = new NpgSqlEnititesContext(_options); 35 | ctx.Database.EnsureDeleted(); 36 | ctx.Database.EnsureCreated(); 37 | ctx.Database.ExecuteSqlRaw("create schema \"views\""); 38 | ctx.Database.ExecuteSqlRaw("create view \"views\".\"EventsView\" as select \"Name\" from \"Events\""); 39 | return ctx; 40 | } 41 | 42 | [Test] 43 | public void TestFunctionsMapping() 44 | { 45 | using (var db = CreateNpgSqlEntitiesContext()) 46 | { 47 | var date = DateTime.Now; 48 | 49 | var query = db.Events.Where(e => 50 | e.Duration.Contains(date) || e.Duration.LowerBound == date || e.Duration.UpperBound == date || 51 | e.Duration.IsEmpty || e.Duration.Intersect(e.Duration).IsEmpty); 52 | 53 | var efResult = query.ToArray(); 54 | var l2dbResult = query.ToLinqToDB().ToArray(); 55 | } 56 | } 57 | 58 | [Test] 59 | public void TestViewMapping() 60 | { 61 | using (var db = CreateNpgSqlEntitiesContext()) 62 | { 63 | var query = db.Set().Where(e => 64 | e.Name.StartsWith("any")); 65 | 66 | var efResult = query.ToArray(); 67 | var l2dbResult = query.ToLinqToDB().ToArray(); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/AAA.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 5 | { 6 | public class Unit 7 | { 8 | 9 | } 10 | 11 | public static class ExceptionExtensions 12 | { 13 | public static Unit Throw(this Exception e) => throw e; 14 | } 15 | 16 | public static class AAA 17 | { 18 | public static ArrangeResult Arrange(this T @object, Action action) 19 | { 20 | action(@object); 21 | return new ArrangeResult(@object, default); 22 | } 23 | 24 | public static ArrangeResult Arrange(T @object) 25 | => new ArrangeResult(@object, default); 26 | 27 | public static ArrangeResult Arrange(this TMock mock, Func @object) 28 | where TMock: notnull 29 | => new ArrangeResult(@object(mock), mock); 30 | 31 | public static ActResult Act(this ArrangeResult arrange, Action act) 32 | where T : notnull 33 | where TMock : notnull 34 | { 35 | try 36 | { 37 | act(arrange.Object); 38 | return new ActResult(arrange.Object, arrange.Mock, default); 39 | } 40 | catch (Exception e) 41 | { 42 | return new ActResult(arrange.Object, arrange.Mock, e); 43 | } 44 | } 45 | 46 | public static ActResult Act(this ArrangeResult arrange, Func act) 47 | where TResult : notnull 48 | where TMock : notnull 49 | { 50 | try 51 | { 52 | return new ActResult(act(arrange.Object), arrange.Mock, default); 53 | } 54 | catch (Exception e) 55 | { 56 | return new ActResult(default, arrange.Mock, e); 57 | } 58 | } 59 | 60 | public static void Assert(this ActResult act, Action assert) 61 | where T : notnull 62 | where TMock : notnull 63 | { 64 | act.Exception?.Throw(); 65 | assert(act.Object); 66 | } 67 | 68 | public static void Assert(this ActResult act, Action assert) 69 | where T : notnull 70 | where TMock : notnull 71 | { 72 | act.Exception?.Throw(); 73 | assert(act.Object, act.Mock); 74 | } 75 | 76 | public static Task> ArrangeAsync(T @object) 77 | => Task.FromResult(new ArrangeResult(@object, default)); 78 | 79 | public static async Task> Act(this Task> arrange, Func> act) 80 | where TMock : notnull 81 | where TResult : notnull 82 | { 83 | var a = await arrange; 84 | try 85 | { 86 | return new ActResult(await act(a.Object), a.Mock, default); 87 | } 88 | catch (Exception e) 89 | { 90 | return new ActResult(default, a.Mock, e); 91 | } 92 | } 93 | 94 | public static async Task Assert(this Task> act, Func assert) 95 | where T : notnull 96 | where TMock : notnull 97 | { 98 | var result = await act; 99 | await assert(result.Object); 100 | } 101 | 102 | public readonly struct ArrangeResult 103 | where TMock : notnull 104 | { 105 | internal ArrangeResult(T @object, TMock? mock) => (Object, Mock) = (@object, mock); 106 | internal T Object { get; } 107 | internal TMock Mock { get; } 108 | } 109 | 110 | public readonly struct ActResult 111 | where T: notnull 112 | { 113 | internal ActResult(T? @object, TMock mock, Exception? exception) 114 | => (Object, Mock, Exception) = (@object, mock, exception); 115 | internal T Object { get; } 116 | internal TMock Mock { get; } 117 | internal Exception? Exception { get; } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/Child.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 2 | { 3 | public sealed class Child : IHasWriteableId 4 | { 5 | public Id Id { get; set; } 6 | public Id ParentId { get; set; } 7 | public string Name { get; set; } = null!; 8 | public Entity Parent { get; set; } = null!; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/DataContextExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 2 | { 3 | public static class DataContextExtensions 4 | { 5 | public static Id Insert(this IDataContext context, T item) 6 | where T : IHasWriteableId 7 | { 8 | item.Id = context.InsertWithInt64Identity(item).AsId(); 9 | return item.Id; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/Detail.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 4 | { 5 | public sealed class Detail : IHasWriteableId 6 | { 7 | public Id Id { get; set; } 8 | public Id MasterId { get; set; } 9 | public string Name { get; set; } = null!; 10 | public Entity Master { get; set; } = null!; 11 | public IEnumerable Details { get; set; } = null!; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/Entity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 4 | { 5 | public sealed class Entity : IHasWriteableId 6 | { 7 | public Id Id { get; set; } 8 | public string Name { get; set; } = null!; 9 | 10 | public IEnumerable Details { get; set; } = null!; 11 | public IEnumerable Children { get; set; } = null!; 12 | public IEnumerable Items { get; set; } = null!; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/Entity2Item.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 2 | { 3 | public sealed class Entity2Item 4 | { 5 | public Id EntityId { get; set; } 6 | public Entity Entity { get; set; } = null!; 7 | public Id ItemId { get; set; } 8 | 9 | public Entity2Item() 10 | { 11 | } 12 | 13 | public Item Item { get; set; } = null!; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/IHasId.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 2 | { 3 | public interface IHasId 4 | where T: IHasId 5 | where TId : notnull 6 | { 7 | Id Id { get; } 8 | } 9 | 10 | public interface IHasWriteableId : IHasId 11 | where T: IHasWriteableId 12 | where TId : notnull 13 | { 14 | new Id Id { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/Id.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 4 | { 5 | public static class Id 6 | { 7 | public static Id AsId(this long id) where T : IHasId => id.AsId(); 8 | 9 | public static Id AsId(this TId id) 10 | where T : IHasId 11 | where TId : notnull 12 | => new Id(id); 13 | } 14 | 15 | public readonly struct Id 16 | where T : IHasId 17 | where TId : notnull 18 | { 19 | internal Id(TId value) => Value = value; 20 | TId Value { get; } 21 | 22 | public static implicit operator TId (in Id id) => id.Value; 23 | public static bool operator == (Id left, Id right) 24 | => EqualityComparer.Default.Equals(left.Value, right.Value); 25 | public static bool operator != (Id left, Id right) => !(left == right); 26 | 27 | public override string ToString() => $"{typeof(T).Name}({Value})"; 28 | public bool Equals(Id other) => EqualityComparer.Default.Equals(Value, other.Value); 29 | public override bool Equals(object? obj) => obj is Id other && Equals(other); 30 | public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Value); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/IdTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using FluentAssertions; 5 | using LinqToDB.Common.Logging; 6 | using LinqToDB.EntityFrameworkCore.BaseTests; 7 | using Microsoft.EntityFrameworkCore; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | using NUnit.Framework; 10 | 11 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 12 | { 13 | [TestFixture] 14 | public sealed class IdTests : IDisposable 15 | { 16 | public IdTests() 17 | { 18 | _efContext = new TestContext( 19 | new DbContextOptionsBuilder() 20 | .ReplaceService() 21 | .UseLoggerFactory(TestUtils.LoggerFactory) 22 | .EnableSensitiveDataLogging() 23 | .UseNpgsql("Server=DBHost;Port=5432;Database=TestData;User Id=postgres;Password=TestPassword;Pooling=true;MinPoolSize=10;MaxPoolSize=100;") 24 | .Options); 25 | _efContext.Database.EnsureDeleted(); 26 | _efContext.Database.EnsureCreated(); 27 | } 28 | 29 | IDataContext CreateLinqToDbContext(TestContext testContext) 30 | { 31 | var result = testContext.CreateLinqToDbContext(); 32 | result.GetTraceSwitch().Level = TraceLevel.Verbose; 33 | return result; 34 | } 35 | 36 | readonly TestContext _efContext; 37 | 38 | [Test] 39 | [Ignore("Incomplete.")] 40 | public void TestInsertWithoutTracker([Values("test insert")] string name) 41 | => _efContext 42 | .Arrange(c => CreateLinqToDbContext(c)) 43 | .Act(c => c.Insert(new Entity { Name = name })) 44 | .Assert(id => _efContext.Entitites.Single(e => e.Id == id).Name.Should().Be(name)); 45 | 46 | [Test] 47 | [Ignore("Incomplete.")] 48 | public void TestInsertWithoutNew([Values("test insert")] string name) 49 | => _efContext.Entitites 50 | .Arrange(e => e.ToLinqToDBTable()) 51 | .Act(e => e.InsertWithInt64Identity(() => new Entity {Name = name})) 52 | .Assert(id => _efContext.Entitites.Single(e => e.Id == id).Name.Should().Be(name)); 53 | 54 | [Test] 55 | [Ignore("Incomplete.")] 56 | public void TestInsertEfCore([Values("test insert ef")] string name) 57 | => _efContext 58 | .Arrange(c => c.Entitites.Add(new Entity {Name = "test insert ef"})) 59 | .Act(_ => _efContext.SaveChanges()) 60 | .Assert(_ => _efContext.Entitites.Single().Name.Should().Be(name)); 61 | 62 | [Test] 63 | [Ignore("Incomplete.")] 64 | public void TestIncludeDetails([Values] bool l2db, [Values] bool tracking) 65 | => _efContext 66 | .Arrange(c => InsertDefaults(CreateLinqToDbContext(c))) 67 | .Act(c => c 68 | .Entitites 69 | .Where(e => e.Name == "Alpha") 70 | .Include(e => e.Details) 71 | .ThenInclude(d => d.Details) 72 | .Include(e => e.Children) 73 | .AsLinqToDb(l2db) 74 | .AsTracking(tracking) 75 | .ToArray()) 76 | .Assert(e => e.First().Details.First().Details.Count().Should().Be(2)); 77 | 78 | [Test] 79 | public void TestManyToManyIncludeTrackerPoison([Values] bool l2db) 80 | => _efContext 81 | .Arrange(c => InsertDefaults(CreateLinqToDbContext(c))) 82 | .Act(c => 83 | { 84 | var q = c.Entitites 85 | .Include(e => e.Items) 86 | .ThenInclude(x => x.Item); 87 | var f = q.AsLinqToDb(l2db).AsTracking().ToArray(); 88 | var s = q.AsLinqToDb(!l2db).AsTracking().ToArray(); 89 | return (First: f, Second: s); 90 | }) 91 | .Assert(r => r.First[0].Items.Count().Should().Be(r.Second[0].Items.Count())); 92 | 93 | 94 | [Test] 95 | [Ignore("Incomplete.")] 96 | public void TestManyToManyInclude([Values] bool l2db, [Values] bool tracking) 97 | => _efContext 98 | .Arrange(c => InsertDefaults(CreateLinqToDbContext(c))) 99 | .Act(c => c.Entitites 100 | .Include(e => e.Items) 101 | .ThenInclude(x => x.Item) 102 | .AsLinqToDb(l2db) 103 | .AsTracking(tracking) 104 | .ToArray()) 105 | .Assert(m => m[0].Items.First().Item.Should().BeSameAs(m[1].Items.First().Item)); 106 | 107 | [Test] 108 | [Ignore("Incomplete.")] 109 | public void TestMasterInclude([Values] bool l2db, [Values] bool tracking) 110 | => _efContext 111 | .Arrange(c => InsertDefaults(CreateLinqToDbContext(c))) 112 | .Act(c => c 113 | .Details 114 | .Include(d => d.Master) 115 | .AsLinqToDb(l2db) 116 | .AsTracking(tracking) 117 | .ToArray()) 118 | .Assert(m => m[0].Master.Should().BeSameAs(m[1].Master)); 119 | 120 | [Test] 121 | [Ignore("Incomplete.")] 122 | public void TestMasterInclude2([Values] bool l2db, [Values] bool tracking) 123 | => _efContext 124 | .Arrange(c => InsertDefaults(CreateLinqToDbContext(c))) 125 | .Act(c => c 126 | .Details 127 | .Include(d => d.Master) 128 | .AsTracking(tracking) 129 | .AsLinqToDb(l2db) 130 | .ToArray()) 131 | .Assert(m => m[0].Master.Should().BeSameAs(m[1].Master)); 132 | 133 | void InsertDefaults(IDataContext dataContext) 134 | { 135 | var a = dataContext.Insert(new Entity {Name = "Alpha"}); 136 | var b = dataContext.Insert(new Entity {Name = "Bravo"}); 137 | var d = dataContext.Insert(new Detail {Name = "First", MasterId = a}); 138 | var r = dataContext.Insert(new Item {Name = "Red"}); 139 | var g = dataContext.Insert(new Item {Name = "Green"}); 140 | var w = dataContext.Insert(new Item {Name = "White"}); 141 | 142 | dataContext.Insert(new Detail {Name = "Second", MasterId = a}); 143 | dataContext.Insert(new SubDetail {Name = "Plus", MasterId = d}); 144 | dataContext.Insert(new SubDetail {Name = "Minus", MasterId = d}); 145 | dataContext.Insert(new Child {Name = "One", ParentId = a}); 146 | dataContext.Insert(new Child {Name = "Two", ParentId = a}); 147 | dataContext.Insert(new Child {Name = "Three", ParentId = a}); 148 | dataContext.Insert(new Entity2Item {EntityId = a, ItemId = r}); 149 | dataContext.Insert(new Entity2Item {EntityId = a, ItemId = g}); 150 | dataContext.Insert(new Entity2Item {EntityId = b, ItemId = r}); 151 | dataContext.Insert(new Entity2Item {EntityId = b, ItemId = w}); 152 | } 153 | 154 | public class TestContext : DbContext 155 | { 156 | public TestContext(DbContextOptions options) : base(options) { } 157 | protected override void OnModelCreating(ModelBuilder modelBuilder) 158 | { 159 | base.OnModelCreating(modelBuilder); 160 | modelBuilder.Entity().HasKey(x => new { x.EntityId, x.ItemId}); 161 | modelBuilder 162 | .UseSnakeCase() 163 | .UseIdAsKey() 164 | .UseOneIdSequence("test", sn => $"nextval('{sn}')"); 165 | } 166 | 167 | 168 | public DbSet Entitites { get; set; } = null!; 169 | public DbSet Details { get; set; } = null!; 170 | public DbSet SubDetails { get; set; } = null!; 171 | public DbSet Items { get; set; } = null!; 172 | public DbSet Children { get; set; } = null!; 173 | } 174 | 175 | public void Dispose() => _efContext.Dispose(); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/IdValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 6 | { 7 | public sealed class IdValueConverter : ValueConverter, TId> 8 | where T : IHasId 9 | where TId : notnull 10 | { 11 | public IdValueConverter(ConverterMappingHints? mappingHints = null) 12 | : base(id => id, id => id.AsId()) { } 13 | } 14 | 15 | public sealed class IdValueConverterSelector : ValueConverterSelector 16 | { 17 | public IdValueConverterSelector([System.Diagnostics.CodeAnalysis.NotNull] ValueConverterSelectorDependencies dependencies) : base(dependencies) 18 | { 19 | } 20 | 21 | public override IEnumerable Select(Type modelClrType, Type? providerClrType = null) 22 | { 23 | var baseConverters = base.Select(modelClrType, providerClrType); 24 | foreach (var converter in baseConverters) 25 | yield return converter; 26 | 27 | modelClrType = modelClrType.UnwrapNullable(); 28 | providerClrType = providerClrType.UnwrapNullable(); 29 | 30 | if (!modelClrType.IsGenericType) 31 | yield break; 32 | 33 | if (modelClrType.GetGenericTypeDefinition() != typeof(Id<,>)) 34 | yield break; 35 | 36 | var t = modelClrType.GetGenericArguments(); 37 | var key = t[1]; 38 | providerClrType ??= key; 39 | if (key != providerClrType) 40 | yield break; 41 | 42 | var ct = typeof(IdValueConverter<,>).MakeGenericType(key, t[0]); 43 | yield return new ValueConverterInfo 44 | ( 45 | modelClrType, 46 | providerClrType, 47 | i => (ValueConverter)Activator.CreateInstance(ct, i.MappingHints)! 48 | ); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/Item.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 2 | { 3 | public sealed class Item : IHasWriteableId 4 | { 5 | public Id Id { get; set; } 6 | public string Name { get; set; } = null!; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/ModelBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | 7 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 8 | { 9 | public static class ModelBuilderExtensions 10 | { 11 | public static ModelBuilder UseIdAsKey(this ModelBuilder modelBuilder) 12 | { 13 | var entities = modelBuilder.Model.GetEntityTypes().Select(e => e.ClrType).ToHashSet(); 14 | 15 | // For all entities in the data model 16 | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) 17 | { 18 | // Find the properties that are our strongly-typed ID 19 | var properties = entityType 20 | .ClrType 21 | .GetProperties() 22 | .Where(p => 23 | { 24 | var unwrappedType = p.PropertyType.UnwrapNullable(); 25 | return unwrappedType.IsGenericType && unwrappedType.GetGenericTypeDefinition() == typeof(Id<,>); 26 | }); 27 | 28 | foreach (var property in properties) 29 | { 30 | var entity = property.PropertyType.UnwrapNullable().GetGenericArguments()[0]; 31 | 32 | if (!entities.Contains(entity)) 33 | continue; 34 | 35 | if (entity == entityType.ClrType && property.Name == "Id") 36 | { 37 | modelBuilder 38 | .Entity(entityType.Name) 39 | .HasKey(property.Name); 40 | continue; 41 | } 42 | 43 | var oneNavigation = entityType.ClrType.GetProperties() 44 | .SingleOrDefault(p => p.PropertyType == entity); 45 | var manyNavigation = entity.GetProperties() 46 | .SingleOrDefault(p => 47 | { 48 | var pt = p.PropertyType; 49 | return pt.IsGenericType 50 | && pt.GetGenericTypeDefinition() == typeof(IEnumerable<>) 51 | && pt.GetGenericArguments()[0] == entityType.ClrType; 52 | }); 53 | 54 | modelBuilder 55 | .Entity(entityType.Name) 56 | .HasOne(entity, oneNavigation?.Name) 57 | .WithMany(manyNavigation?.Name) 58 | .HasForeignKey(property.Name) 59 | .OnDelete(DeleteBehavior.Restrict); 60 | } 61 | } 62 | 63 | return modelBuilder; 64 | 65 | 66 | } 67 | 68 | public static ModelBuilder UseOneIdSequence(this ModelBuilder modelBuilder, string sequenceName, Func nextval) 69 | { 70 | modelBuilder.HasSequence(sequenceName); 71 | var entities = modelBuilder.Model.GetEntityTypes().Select(e => e.ClrType).ToHashSet(); 72 | 73 | // For all entities in the data model 74 | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) 75 | { 76 | // Find the properties that are our strongly-typed ID 77 | var id = entityType 78 | .ClrType 79 | .GetProperties() 80 | .FirstOrDefault(p => p.PropertyType.IsGenericType 81 | && p.PropertyType.GetGenericTypeDefinition() == typeof(Id<,>) 82 | && p.PropertyType.GetGenericArguments()[0] == entityType.ClrType 83 | && p.PropertyType.GetGenericArguments()[1] == typeof(T) 84 | && p.Name == "Id"); 85 | 86 | if (id == null) 87 | continue; 88 | 89 | modelBuilder 90 | .Entity(entityType.Name) 91 | .Property(id.Name) 92 | .HasDefaultValueSql(nextval(sequenceName)) 93 | .ValueGeneratedOnAdd(); 94 | } 95 | 96 | return modelBuilder; 97 | } 98 | 99 | public static ModelBuilder UseSnakeCase(this ModelBuilder modelBuilder) 100 | { 101 | modelBuilder.Model.SetDefaultSchema(modelBuilder.Model.GetDefaultSchema().ToSnakeCase()); 102 | foreach (var entity in modelBuilder.Model.GetEntityTypes()) 103 | { 104 | entity.SetTableName(entity.GetTableName().ToSnakeCase()); 105 | var storeObjectId = StoreObjectIdentifier.Create(entity, StoreObjectType.Table); 106 | 107 | foreach (var property in entity.GetProperties()) 108 | { 109 | property.SetColumnName(property.GetColumnName(storeObjectId!.Value).ToSnakeCase()); 110 | } 111 | 112 | foreach (var key in entity.GetKeys()) 113 | key.SetName(key.GetName().ToSnakeCase()); 114 | 115 | foreach (var key in entity.GetForeignKeys()) 116 | key.SetConstraintName(key.GetConstraintName().ToSnakeCase()); 117 | 118 | foreach (var index in entity.GetIndexes()) 119 | index.SetDatabaseName(index.GetDatabaseName().ToSnakeCase()); 120 | } 121 | return modelBuilder; 122 | } 123 | 124 | public static ModelBuilder UsePermanentId(this ModelBuilder modelBuilder) 125 | { 126 | // For all entities in the data model 127 | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) 128 | { 129 | // Find the properties that are our strongly-typed ID 130 | var properties = entityType 131 | .ClrType 132 | .GetProperties() 133 | .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Id<,>)); 134 | 135 | foreach (var property in properties) 136 | { 137 | var entity = property.PropertyType.GetGenericArguments()[0]; 138 | 139 | if (entity != entityType.ClrType || property.Name != "PermanentId") 140 | continue; 141 | 142 | modelBuilder 143 | .Entity(entityType.Name) 144 | .HasIndex(property.Name) 145 | .IsUnique(); 146 | } 147 | } 148 | return modelBuilder; 149 | } 150 | 151 | public static ModelBuilder UseCode(this ModelBuilder modelBuilder) 152 | { 153 | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) 154 | { 155 | var properties = entityType 156 | .ClrType 157 | .GetProperties(); 158 | 159 | foreach (var property in properties) 160 | { 161 | if (property.Name != "Code") 162 | continue; 163 | 164 | modelBuilder 165 | .Entity(entityType.Name) 166 | .HasIndex(property.Name) 167 | .IsUnique(); 168 | } 169 | } 170 | return modelBuilder; 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/QueryableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 5 | { 6 | public static class QueryableExtensions 7 | { 8 | public static IQueryable AsLinqToDb(this IQueryable queryable, bool l2db) 9 | => l2db ? queryable.ToLinqToDB() : queryable; 10 | 11 | public static IQueryable AsTracking(this IQueryable queryable, bool tracking) 12 | where T : class 13 | => tracking ? queryable.AsTracking() : queryable.AsNoTracking(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 4 | { 5 | public static class StringExtensions 6 | { 7 | public static string ToSnakeCase(this string input) 8 | { 9 | if (string.IsNullOrEmpty(input)) 10 | return input; 11 | 12 | var startUnderscores = Regex.Match(input, @"^_+"); 13 | return startUnderscores + Regex.Replace(input, @"([a-z0-9])([A-Z])", "$1_$2").ToLower(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/SubDetail.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 2 | { 3 | public sealed class SubDetail : IHasWriteableId 4 | { 5 | public Id Id { get; set; } 6 | public Id MasterId { get; set; } 7 | public string Name { get; set; } = null!; 8 | public Detail Master { get; set; } = null!; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.PostgreSQL.Tests/SampleTests/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.SampleTests 5 | { 6 | public static class TypeExtensions 7 | { 8 | [return: NotNullIfNotNull("type")] 9 | public static Type? UnwrapNullable(this Type? type) 10 | => type == null ? null : Nullable.GetUnderlyingType(type) ?? type; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/CategoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class CategoriesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.CategoryId); 13 | 14 | builder.HasIndex(e => e.CategoryName) 15 | .HasDatabaseName("CategoryName"); 16 | 17 | builder.Property(e => e.CategoryId).HasColumnName("CategoryID") 18 | /*.ValueGeneratedNever()*/; 19 | 20 | builder.Property(e => e.CategoryName) 21 | .IsRequired() 22 | .HasMaxLength(15); 23 | 24 | builder.Property(e => e.Description).HasColumnType("text"); 25 | 26 | builder.Property(e => e.Picture).HasColumnType("blob"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/CustomerCustomerDemoMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomerCustomerDemoMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => new { e.CustomerId, e.CustomerTypeId }); 13 | 14 | builder.Property(e => e.CustomerId) 15 | .HasColumnName("CustomerID") 16 | .HasMaxLength(5); 17 | 18 | builder.Property(e => e.CustomerTypeId) 19 | .HasColumnName("CustomerTypeID") 20 | .HasMaxLength(10); 21 | 22 | builder.HasOne(d => d.Customer) 23 | .WithMany(p => p.CustomerCustomerDemo) 24 | .HasForeignKey(d => d.CustomerId) 25 | .OnDelete(DeleteBehavior.ClientSetNull) 26 | .HasConstraintName("FK_CustomerCustomerDemo_Customers"); 27 | 28 | builder.HasOne(d => d.CustomerType) 29 | .WithMany(p => p.CustomerCustomerDemo) 30 | .HasForeignKey(d => d.CustomerTypeId) 31 | .OnDelete(DeleteBehavior.ClientSetNull) 32 | .HasConstraintName("FK_CustomerCustomerDemo"); 33 | 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/CustomerDemographicsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomerDemographicsMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.CustomerTypeId); 12 | 13 | builder.Property(e => e.CustomerTypeId) 14 | .HasColumnName("CustomerTypeID") 15 | .HasMaxLength(10) 16 | .ValueGeneratedNever(); 17 | 18 | builder.Property(e => e.CustomerDesc).HasColumnType("text"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/CustomersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomersMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.CustomerId); 13 | 14 | builder.HasIndex(e => e.City) 15 | .HasDatabaseName("City"); 16 | 17 | builder.HasIndex(e => e.CompanyName) 18 | .HasDatabaseName("Customer_CompanyName"); 19 | 20 | builder.HasIndex(e => e.PostalCode) 21 | .HasDatabaseName("Customer_Postal_ode"); 22 | 23 | builder.HasIndex(e => e.Region) 24 | .HasDatabaseName("Customer_Region"); 25 | 26 | builder.Property(e => e.CustomerId) 27 | .HasColumnName("CustomerID") 28 | .HasMaxLength(5) 29 | .ValueGeneratedNever(); 30 | 31 | builder.Property(e => e.Address).HasMaxLength(60); 32 | builder.Property(e => e.City).HasMaxLength(15); 33 | builder.Property(e => e.CompanyName) 34 | .IsRequired() 35 | .HasMaxLength(40); 36 | 37 | builder.Property(e => e.ContactName).HasMaxLength(30); 38 | builder.Property(e => e.ContactTitle).HasMaxLength(30); 39 | builder.Property(e => e.Country).HasMaxLength(15); 40 | builder.Property(e => e.Fax).HasMaxLength(24); 41 | builder.Property(e => e.Phone).HasMaxLength(24); 42 | builder.Property(e => e.PostalCode).HasMaxLength(10); 43 | builder.Property(e => e.Region).HasMaxLength(15); 44 | 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/EmployeeTerritoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class EmployeeTerritoriesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => new { e.EmployeeId, e.TerritoryId }); 12 | 13 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID"); 14 | 15 | builder.Property(e => e.TerritoryId) 16 | .HasColumnName("TerritoryID") 17 | .HasMaxLength(20); 18 | 19 | builder.HasOne(d => d.Employee) 20 | .WithMany(p => p.EmployeeTerritories) 21 | .HasForeignKey(d => d.EmployeeId) 22 | .OnDelete(DeleteBehavior.ClientSetNull) 23 | .HasConstraintName("FK_EmployeeTerritories_Employees"); 24 | 25 | builder.HasOne(d => d.Territory) 26 | .WithMany(p => p.EmployeeTerritories) 27 | .HasForeignKey(d => d.TerritoryId) 28 | .OnDelete(DeleteBehavior.ClientSetNull) 29 | .HasConstraintName("FK_EmployeeTerritories_Territories"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/EmployeesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class EmployeesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.EmployeeId); 12 | 13 | builder.HasIndex(e => e.LastName) 14 | .HasDatabaseName("Employee_LastName"); 15 | 16 | builder.HasIndex(e => e.PostalCode) 17 | .HasDatabaseName("Employee_PostalCode"); 18 | 19 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID") 20 | .ValueGeneratedNever(); 21 | 22 | builder.Property(e => e.Address).HasMaxLength(60); 23 | 24 | builder.Property(e => e.BirthDate).HasColumnType("datetime"); 25 | 26 | builder.Property(e => e.City).HasMaxLength(15); 27 | 28 | builder.Property(e => e.Country).HasMaxLength(15); 29 | 30 | builder.Property(e => e.Extension).HasMaxLength(4); 31 | 32 | builder.Property(e => e.FirstName) 33 | .IsRequired() 34 | .HasMaxLength(10); 35 | 36 | builder.Property(e => e.HireDate).HasColumnType("datetime"); 37 | 38 | builder.Property(e => e.HomePhone).HasMaxLength(24); 39 | 40 | builder.Property(e => e.LastName) 41 | .IsRequired() 42 | .HasMaxLength(20); 43 | 44 | builder.Property(e => e.Notes).HasColumnType("text"); 45 | 46 | builder.Property(e => e.Photo).HasColumnType("blob"); 47 | 48 | builder.Property(e => e.PhotoPath).HasMaxLength(255); 49 | 50 | builder.Property(e => e.PostalCode).HasMaxLength(10); 51 | 52 | builder.Property(e => e.Region).HasMaxLength(15); 53 | 54 | builder.Property(e => e.Title).HasMaxLength(30); 55 | 56 | builder.Property(e => e.TitleOfCourtesy).HasMaxLength(25); 57 | 58 | builder.HasOne(d => d.ReportsToNavigation) 59 | .WithMany(p => p!.InverseReportsToNavigation) 60 | .HasForeignKey(d => d.ReportsTo) 61 | .HasConstraintName("FK_Employees_Employees"); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/OrderDetailsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class OrderDetailsMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => new { e.OrderId, e.ProductId }); 12 | 13 | builder.ToTable("Order Details"); 14 | 15 | builder.HasIndex(e => e.OrderId) 16 | .HasDatabaseName("OrdersOrder_Details"); 17 | 18 | builder.HasIndex(e => e.ProductId) 19 | .HasDatabaseName("ProductsOrder_Details"); 20 | 21 | builder.Property(e => e.OrderId).HasColumnName("OrderID"); 22 | 23 | builder.Property(e => e.ProductId).HasColumnName("ProductID"); 24 | 25 | builder.Property(e => e.Quantity).HasDefaultValue(1); 26 | 27 | builder.Property(e => e.UnitPrice).HasColumnType("decimal(13, 4)"); 28 | 29 | builder.HasOne(d => d.Order) 30 | .WithMany(p => p.OrderDetails) 31 | .HasForeignKey(d => d.OrderId) 32 | .OnDelete(DeleteBehavior.ClientSetNull) 33 | .HasConstraintName("FK_Order_Details_Orders"); 34 | 35 | builder.HasOne(d => d.Product) 36 | .WithMany(p => p.OrderDetails) 37 | .HasForeignKey(d => d.ProductId) 38 | .OnDelete(DeleteBehavior.ClientSetNull) 39 | .HasConstraintName("FK_Order_Details_Products"); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/OrderMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class OrderMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.OrderId); 13 | 14 | builder.HasIndex(e => e.CustomerId) 15 | .HasDatabaseName("Order_CustomersOrders"); 16 | 17 | builder.HasIndex(e => e.EmployeeId) 18 | .HasDatabaseName("Order_EmployeesOrders"); 19 | 20 | builder.HasIndex(e => e.OrderDate) 21 | .HasDatabaseName("Order_OrderDate"); 22 | 23 | builder.HasIndex(e => e.ShipPostalCode) 24 | .HasDatabaseName("Order_ShipPostalCode"); 25 | 26 | builder.HasIndex(e => e.ShipVia) 27 | .HasDatabaseName("Order_ShippersOrders"); 28 | 29 | builder.HasIndex(e => e.ShippedDate) 30 | .HasDatabaseName("Order_ShippedDate"); 31 | 32 | builder.Property(e => e.OrderId).HasColumnName("OrderID") 33 | .ValueGeneratedNever(); 34 | 35 | builder.Property(e => e.CustomerId) 36 | .HasColumnName("CustomerID") 37 | .HasMaxLength(5); 38 | 39 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID"); 40 | 41 | builder.Property(e => e.Freight) 42 | .HasColumnType("decimal(13, 4)") 43 | .HasDefaultValue(0m); 44 | 45 | builder.Property(e => e.OrderDate).HasColumnType("datetime"); 46 | 47 | builder.Property(e => e.RequiredDate).HasColumnType("datetime"); 48 | 49 | builder.Property(e => e.ShipAddress).HasMaxLength(60); 50 | 51 | builder.Property(e => e.ShipCity).HasMaxLength(15); 52 | 53 | builder.Property(e => e.ShipCountry).HasMaxLength(15); 54 | 55 | builder.Property(e => e.ShipName).HasMaxLength(40); 56 | 57 | builder.Property(e => e.ShipPostalCode).HasMaxLength(10); 58 | 59 | builder.Property(e => e.ShipRegion).HasMaxLength(15); 60 | 61 | builder.Property(e => e.ShippedDate).HasColumnType("datetime"); 62 | 63 | builder.HasOne(d => d.Customer) 64 | .WithMany(p => p!.Orders) 65 | .HasForeignKey(d => d.CustomerId) 66 | .HasConstraintName("FK_Orders_Customers"); 67 | 68 | builder.HasOne(d => d.Employee) 69 | .WithMany(p => p!.Orders) 70 | .HasForeignKey(d => d.EmployeeId) 71 | .HasConstraintName("FK_Orders_Employees"); 72 | 73 | builder.HasOne(d => d.ShipViaNavigation) 74 | .WithMany(p => p!.Orders) 75 | .HasForeignKey(d => d.ShipVia) 76 | .HasConstraintName("FK_Orders_Shippers"); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/ProductsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class ProductsMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.ProductId); 12 | 13 | builder.HasIndex(e => e.CategoryId) 14 | .HasDatabaseName("Product_CategoryID"); 15 | 16 | builder.HasIndex(e => e.ProductName) 17 | .HasDatabaseName("Product_ProductName"); 18 | 19 | builder.HasIndex(e => e.SupplierId) 20 | .HasDatabaseName("Product_SuppliersProducts"); 21 | 22 | builder.Property(e => e.ProductId).HasColumnName("ProductID") 23 | .ValueGeneratedNever(); 24 | 25 | builder.Property(e => e.CategoryId).HasColumnName("CategoryID"); 26 | 27 | builder.Property(e => e.ProductName) 28 | .IsRequired() 29 | .HasMaxLength(40); 30 | 31 | builder.Property(e => e.QuantityPerUnit).HasMaxLength(20); 32 | 33 | builder.Property(e => e.ReorderLevel).HasDefaultValue((short)0); 34 | 35 | builder.Property(e => e.SupplierId).HasColumnName("SupplierID"); 36 | 37 | builder.Property(e => e.UnitPrice) 38 | .HasColumnType("decimal(13, 4)") 39 | .HasDefaultValue(0m); 40 | 41 | builder.Property(e => e.UnitsInStock).HasDefaultValue((short)0); 42 | 43 | builder.Property(e => e.UnitsOnOrder).HasDefaultValue((short)0); 44 | 45 | builder.HasOne(d => d.Category) 46 | .WithMany(p => p!.Products) 47 | .HasForeignKey(d => d.CategoryId) 48 | .HasConstraintName("FK_Products_Categories"); 49 | 50 | builder.HasOne(d => d.Supplier) 51 | .WithMany(p => p!.Products) 52 | .HasForeignKey(d => d.SupplierId) 53 | .HasConstraintName("FK_Products_Suppliers"); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/RegionMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class RegionMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.RegionId); 12 | 13 | builder.Property(e => e.RegionId) 14 | .HasColumnName("RegionID") 15 | .ValueGeneratedNever(); 16 | 17 | builder.Property(e => e.RegionDescription) 18 | .IsRequired() 19 | .HasMaxLength(50); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/ShippersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class ShippersMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.ShipperId); 12 | 13 | builder.Property(e => e.ShipperId).HasColumnName("ShipperID") 14 | .ValueGeneratedNever(); 15 | 16 | builder.Property(e => e.CompanyName) 17 | .IsRequired() 18 | .HasMaxLength(40); 19 | 20 | builder.Property(e => e.Phone).HasMaxLength(24); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/SuppliersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class SuppliersMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | builder.HasKey(e => e.SupplierId); 13 | 14 | builder.HasIndex(e => e.CompanyName) 15 | .HasDatabaseName("Supplier_CompanyName"); 16 | 17 | builder.HasIndex(e => e.PostalCode) 18 | .HasDatabaseName("Supplier_PostalCode"); 19 | 20 | builder.Property(e => e.SupplierId).HasColumnName("SupplierID") 21 | .ValueGeneratedNever(); 22 | 23 | builder.Property(e => e.Address).HasMaxLength(60); 24 | 25 | builder.Property(e => e.City).HasMaxLength(15); 26 | 27 | builder.Property(e => e.CompanyName) 28 | .IsRequired() 29 | .HasMaxLength(40); 30 | 31 | builder.Property(e => e.ContactName).HasMaxLength(30); 32 | 33 | builder.Property(e => e.ContactTitle).HasMaxLength(30); 34 | 35 | builder.Property(e => e.Country).HasMaxLength(15); 36 | 37 | builder.Property(e => e.Fax).HasMaxLength(24); 38 | 39 | builder.Property(e => e.HomePage).HasColumnType("text"); 40 | 41 | builder.Property(e => e.Phone).HasMaxLength(24); 42 | 43 | builder.Property(e => e.PostalCode).HasMaxLength(10); 44 | 45 | builder.Property(e => e.Region).HasMaxLength(15); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind.Mapping/TerritoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping 6 | { 7 | public class TerritoriesMap : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.TerritoryId); 12 | 13 | builder.Property(e => e.TerritoryId) 14 | .HasColumnName("TerritoryID") 15 | .HasMaxLength(20) 16 | .ValueGeneratedNever(); 17 | 18 | builder.Property(e => e.RegionId).HasColumnName("RegionID"); 19 | 20 | builder.Property(e => e.TerritoryDescription) 21 | .IsRequired() 22 | .HasMaxLength(50); 23 | 24 | builder.HasOne(d => d.Region) 25 | .WithMany(p => p.Territories) 26 | .HasForeignKey(d => d.RegionId) 27 | .OnDelete(DeleteBehavior.ClientSetNull) 28 | .HasConstraintName("FK_Territories_Region"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/Models/Northwind/NorthwindContext.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind.Mapping; 3 | using LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind 7 | { 8 | public class NorthwindContext : DbContext 9 | { 10 | public DbSet Categories { get; set; } = null!; 11 | public DbSet CustomerCustomerDemo { get; set; } = null!; 12 | public DbSet CustomerDemographics { get; set; } = null!; 13 | public DbSet Customers { get; set; } = null!; 14 | public DbSet Employees { get; set; } = null!; 15 | public DbSet EmployeeTerritories { get; set; } = null!; 16 | public DbSet OrderDetails { get; set; } = null!; 17 | public DbSet Orders { get; set; } = null!; 18 | public DbSet Products { get; set; } = null!; 19 | public DbSet Region { get; set; } = null!; 20 | public DbSet Shippers { get; set; } = null!; 21 | public DbSet Suppliers { get; set; } = null!; 22 | public DbSet Territories { get; set; } = null!; 23 | 24 | public NorthwindContext(DbContextOptions options) : base(options) 25 | { 26 | 27 | } 28 | 29 | protected override void OnModelCreating(ModelBuilder modelBuilder) 30 | { 31 | modelBuilder.ApplyConfiguration(new CategoriesMap()); 32 | modelBuilder.ApplyConfiguration(new CustomerCustomerDemoMap()); 33 | modelBuilder.ApplyConfiguration(new CustomerDemographicsMap()); 34 | modelBuilder.ApplyConfiguration(new CustomersMap()); 35 | modelBuilder.ApplyConfiguration(new EmployeesMap()); 36 | modelBuilder.ApplyConfiguration(new EmployeeTerritoriesMap()); 37 | modelBuilder.ApplyConfiguration(new OrderDetailsMap()); 38 | modelBuilder.ApplyConfiguration(new OrderMap()); 39 | modelBuilder.ApplyConfiguration(new ProductsMap()); 40 | modelBuilder.ApplyConfiguration(new RegionMap()); 41 | modelBuilder.ApplyConfiguration(new ShippersMap()); 42 | modelBuilder.ApplyConfiguration(new SuppliersMap()); 43 | modelBuilder.ApplyConfiguration(new TerritoriesMap()); 44 | 45 | modelBuilder.Entity() 46 | .HasQueryFilter(e => !IsFilterProducts || e.ProductId > 2); 47 | } 48 | 49 | public bool IsFilterProducts { get; set; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SQLite.Tests/SQLiteTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using LinqToDB.Data; 3 | using LinqToDB.EntityFrameworkCore.BaseTests; 4 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 5 | using LinqToDB.EntityFrameworkCore.SQLite.Tests.Models.Northwind; 6 | using Microsoft.EntityFrameworkCore; 7 | using NUnit.Framework; 8 | 9 | namespace LinqToDB.EntityFrameworkCore.SQLite.Tests 10 | { 11 | public class SQLiteTests : TestsBase 12 | { 13 | private DbContextOptions _options; 14 | 15 | static SQLiteTests() 16 | { 17 | LinqToDBForEFTools.Initialize(); 18 | DataConnection.TurnTraceSwitchOn(); 19 | } 20 | 21 | public SQLiteTests() 22 | { 23 | var optionsBuilder = new DbContextOptionsBuilder(); 24 | //new SqlServerDbContextOptionsBuilder(optionsBuilder); 25 | 26 | optionsBuilder.UseSqlite("Data Source=northwind.db;"); 27 | 28 | optionsBuilder.UseLoggerFactory(TestUtils.LoggerFactory); 29 | 30 | _options = optionsBuilder.Options; 31 | } 32 | 33 | private NorthwindContext CreateSQLiteSqlExntitiesContext() 34 | { 35 | var ctx = new NorthwindContext(_options); 36 | ctx.Database.EnsureDeleted(); 37 | ctx.Database.EnsureCreated(); 38 | return ctx; 39 | } 40 | 41 | 42 | [Test] 43 | public void TestIdentityMapping() 44 | { 45 | using (var ctx = CreateSQLiteSqlExntitiesContext()) 46 | using (var db = ctx.CreateLinqToDbConnection()) 47 | { 48 | var ed = db.MappingSchema.GetEntityDescriptor(typeof(Category)); 49 | var pk = ed.Columns.Where(c => c.IsPrimaryKey).Single(); 50 | 51 | Assert.That(pk.IsIdentity, Is.True); 52 | } 53 | } 54 | 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/IssueTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using LinqToDB.EntityFrameworkCore.BaseTests; 3 | using LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind; 4 | using Microsoft.EntityFrameworkCore; 5 | using NUnit.Framework; 6 | using NUnit.Framework.Constraints; 7 | 8 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests 9 | { 10 | [TestFixture] 11 | public class IssueTests : TestsBase 12 | { 13 | private DbContextOptions _options; 14 | private bool _created; 15 | 16 | public IssueTests() 17 | { 18 | var optionsBuilder = new DbContextOptionsBuilder(); 19 | //new SqlServerDbContextOptionsBuilder(optionsBuilder); 20 | 21 | optionsBuilder.UseSqlServer("Server=.;Database=IssuesEFCore;Integrated Security=SSPI"); 22 | optionsBuilder.UseLoggerFactory(TestUtils.LoggerFactory); 23 | 24 | _options = optionsBuilder.Options; 25 | } 26 | 27 | private IssueContext CreateContext() 28 | { 29 | var ctx = new IssueContext(_options); 30 | 31 | if (!_created) 32 | { 33 | //ctx.Database.EnsureDeleted(); 34 | ctx.Database.EnsureCreated(); 35 | _created = true; 36 | } 37 | return ctx; 38 | } 39 | 40 | 41 | [Test] 42 | public void Issue73Test() 43 | { 44 | using var ctx = CreateContext(); 45 | 46 | var q = ctx.Issue73Entities 47 | .Where(x => x.Name == "Name1_3") 48 | .Select(x => x.Parent!.Name + ">" + x.Name); 49 | 50 | var efItems = q.ToList(); 51 | var linq2dbItems = q.ToLinqToDB().ToList(); 52 | 53 | AreEqual(efItems, linq2dbItems); 54 | } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/JsonConverTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using LinqToDB.EntityFrameworkCore.BaseTests; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Query; 6 | using Microsoft.EntityFrameworkCore.Query.SqlExpressions; 7 | using Newtonsoft.Json; 8 | using NUnit.Framework; 9 | 10 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests 11 | { 12 | 13 | [TestFixture] 14 | public class JsonConverTests : TestsBase 15 | { 16 | private DbContextOptions _options; 17 | 18 | public class LocalizedString 19 | { 20 | public string English { get; set; } = null!; 21 | public string German { get; set; } = null!; 22 | public string Slovak { get; set; } = null!; 23 | } 24 | 25 | public class EventScheduleItemBase 26 | { 27 | public int Id { get; set; } 28 | public virtual LocalizedString NameLocalized { get; set; } = null!; 29 | public virtual string JsonColumn { get; set; } = null!; 30 | } 31 | 32 | public enum CrashEnum : byte 33 | { 34 | OneValue = 0, 35 | OtherValue = 1 36 | } 37 | 38 | public class EventScheduleItem : EventScheduleItemBase 39 | { 40 | public CrashEnum CrashEnum { get; set; } 41 | public Guid GuidColumn { get; set; } 42 | } 43 | 44 | public class JsonConvertContext : DbContext 45 | { 46 | public JsonConvertContext() 47 | { 48 | } 49 | 50 | public JsonConvertContext(DbContextOptions options) 51 | : base(options) 52 | { 53 | } 54 | 55 | 56 | public virtual DbSet EventScheduleItems { get; set; } = null!; 57 | 58 | 59 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 60 | { 61 | if (!optionsBuilder.IsConfigured) optionsBuilder.UseSqlServer("conn string"); 62 | } 63 | 64 | protected override void OnModelCreating(ModelBuilder modelBuilder) 65 | { 66 | modelBuilder.Entity(entity => 67 | { 68 | entity.ToTable("EventScheduleItem"); 69 | entity.Property(e => e.NameLocalized) 70 | .HasColumnName("NameLocalized_JSON") 71 | .HasConversion(v => JsonConvert.SerializeObject(v), 72 | v => JsonConvert.DeserializeObject(v)); 73 | entity.Property(e => e.CrashEnum).HasColumnType("tinyint"); 74 | entity.Property(e => e.GuidColumn).HasColumnType("uniqueidentifier"); 75 | }); 76 | 77 | modelBuilder.HasDbFunction(typeof(JsonConverTests).GetMethod(nameof(JsonConverTests.JsonValue))) 78 | .HasTranslation(e => new SqlFunctionExpression( 79 | "JSON_VALUE", e, true, e.Select(_ => false), typeof(string), null)); 80 | } 81 | } 82 | 83 | public JsonConverTests() 84 | { 85 | var optionsBuilder = new DbContextOptionsBuilder(); 86 | //new SqlServerDbContextOptionsBuilder(optionsBuilder); 87 | 88 | optionsBuilder.UseSqlServer("Server=.;Database=JsonConvertContext;Integrated Security=SSPI"); 89 | optionsBuilder.UseLoggerFactory(TestUtils.LoggerFactory); 90 | 91 | _options = optionsBuilder.Options; 92 | } 93 | 94 | public static string JsonValue(string column, [NotParameterized] string path) 95 | { 96 | throw new NotSupportedException(); 97 | } 98 | 99 | [Test] 100 | public void TestJsonConvert() 101 | { 102 | LinqToDBForEFTools.Initialize(); 103 | 104 | // // converting from string, because usually JSON is stored as string, but it depends on DataProvider 105 | // Mapping.MappingSchema.Default.SetConverter(v => JsonConvert.DeserializeObject(v)); 106 | // 107 | // // here we told linq2db how to pass converted value as DataParameter. 108 | // Mapping.MappingSchema.Default.SetConverter(v => new DataParameter("", JsonConvert.SerializeObject(v), LinqToDB.DataType.NVarChar)); 109 | 110 | using (var ctx = new JsonConvertContext(_options)) 111 | { 112 | ctx.Database.EnsureDeleted(); 113 | ctx.Database.EnsureCreated(); 114 | 115 | ctx.EventScheduleItems.Delete(); 116 | 117 | ctx.EventScheduleItems.Add(new EventScheduleItem() 118 | { 119 | NameLocalized = new LocalizedString() { English = "English", German = "German", Slovak = "Slovak" }, 120 | GuidColumn = Guid.NewGuid() 121 | }); 122 | ctx.SaveChanges(); 123 | 124 | var queryable = ctx.EventScheduleItems 125 | .Where(p => p.Id < 10).ToLinqToDB(); 126 | 127 | var path = "some"; 128 | 129 | var items = queryable 130 | .Select(p => new 131 | { 132 | p.Id, 133 | p.NameLocalized, 134 | p.CrashEnum, 135 | p.GuidColumn, 136 | JsonValue = JsonValue(p.JsonColumn, path) 137 | }); 138 | 139 | var item = items.FirstOrDefault(); 140 | 141 | Assert.That(item.NameLocalized.English, Is.EqualTo("English")); 142 | Assert.That(item.NameLocalized.German, Is.EqualTo("German")); 143 | Assert.That(item.NameLocalized.Slovak, Is.EqualTo("Slovak")); 144 | 145 | //TODO: make it work 146 | // var concrete = queryable.Select(p => new 147 | // { 148 | // p.Id, 149 | // English = p.NameLocalized.English 150 | // }).FirstOrDefault(); 151 | // 152 | // Assert.That(concrete.English, Is.EqualTo("English")); 153 | } 154 | 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/IssueModel/Issue73Entity.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.IssueModel 4 | { 5 | public sealed class Issue73Entity 6 | { 7 | public int Id { get; set; } 8 | 9 | public int? ParentId { get; set; } 10 | 11 | public Issue73Entity? Parent { get; set; } = null!; 12 | public List Childs { get; set; } = null!; 13 | 14 | public string Name { get; set; } = null!; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/IssueModel/IssueContext.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 3 | using LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.IssueModel; 4 | using LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping; 5 | using LinqToDB.Expressions; 6 | using LinqToDB.Extensions; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind 10 | { 11 | public class IssueContext : DbContext 12 | { 13 | public DbSet Issue73Entities { get; set; } = null!; 14 | 15 | public IssueContext(DbContextOptions options) : base(options) 16 | { 17 | 18 | } 19 | 20 | protected override void OnModelCreating(ModelBuilder modelBuilder) 21 | { 22 | modelBuilder.Entity(b => 23 | { 24 | b.HasKey(x => new { x.Id }); 25 | 26 | b.HasOne(x => x.Parent) 27 | .WithMany(x => x!.Childs) 28 | .HasForeignKey(x => new { x.ParentId }) 29 | .HasPrincipalKey(x => new { x!.Id }); 30 | 31 | b.HasData(new[] 32 | { 33 | new Issue73Entity 34 | { 35 | Id = 2, 36 | Name = "Name1_2", 37 | }, 38 | new Issue73Entity 39 | { 40 | Id = 3, 41 | Name = "Name1_3", 42 | ParentId = 2 43 | }, 44 | }); 45 | }); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/BaseEntityMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class BaseEntityMap : IEntityTypeConfiguration 8 | where T: BaseEntity 9 | { 10 | public virtual void Configure(EntityTypeBuilder builder) 11 | { 12 | builder.Property(e => e.IsDeleted).HasDefaultValue(false); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/CategoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CategoriesMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.CategoryId); 14 | 15 | builder.HasIndex(e => e.CategoryName) 16 | .HasDatabaseName("CategoryName"); 17 | 18 | builder.Property(e => e.CategoryId).HasColumnName("CategoryID") 19 | .ValueGeneratedNever(); 20 | 21 | builder.Property(e => e.CategoryName) 22 | .IsRequired() 23 | .HasMaxLength(15); 24 | 25 | builder.Property(e => e.Description).HasColumnType("ntext"); 26 | 27 | builder.Property(e => e.Picture).HasColumnType("image"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/CustomerCustomerDemoMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomerCustomerDemoMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | 14 | builder.HasKey(e => new { e.CustomerId, e.CustomerTypeId }) 15 | .IsClustered(false); 16 | 17 | builder.Property(e => e.CustomerId) 18 | .HasColumnName("CustomerID") 19 | .HasMaxLength(5); 20 | 21 | builder.Property(e => e.CustomerTypeId) 22 | .HasColumnName("CustomerTypeID") 23 | .HasMaxLength(10); 24 | 25 | builder.HasOne(d => d.Customer) 26 | .WithMany(p => p.CustomerCustomerDemo) 27 | .HasForeignKey(d => d.CustomerId) 28 | .OnDelete(DeleteBehavior.ClientSetNull) 29 | .HasConstraintName("FK_CustomerCustomerDemo_Customers"); 30 | 31 | builder.HasOne(d => d.CustomerType) 32 | .WithMany(p => p.CustomerCustomerDemo) 33 | .HasForeignKey(d => d.CustomerTypeId) 34 | .OnDelete(DeleteBehavior.ClientSetNull) 35 | .HasConstraintName("FK_CustomerCustomerDemo"); 36 | 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/CustomerDemographicsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomerDemographicsMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.CustomerTypeId) 14 | .IsClustered(false); 15 | 16 | builder.Property(e => e.CustomerTypeId) 17 | .HasColumnName("CustomerTypeID") 18 | .HasMaxLength(10) 19 | .ValueGeneratedNever(); 20 | 21 | builder.Property(e => e.CustomerDesc).HasColumnType("ntext"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/CustomersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class CustomersMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.CustomerId); 14 | 15 | builder.HasIndex(e => e.City) 16 | .HasDatabaseName("City"); 17 | 18 | builder.HasIndex(e => e.CompanyName) 19 | .HasDatabaseName("CompanyName"); 20 | 21 | builder.HasIndex(e => e.PostalCode) 22 | .HasDatabaseName("PostalCode"); 23 | 24 | builder.HasIndex(e => e.Region) 25 | .HasDatabaseName("Region"); 26 | 27 | builder.Property(e => e.CustomerId) 28 | .HasColumnName("CustomerID") 29 | .HasMaxLength(5) 30 | .ValueGeneratedNever(); 31 | 32 | builder.Property(e => e.Address).HasMaxLength(60); 33 | builder.Property(e => e.City).HasMaxLength(15); 34 | builder.Property(e => e.CompanyName) 35 | .IsRequired() 36 | .HasMaxLength(40); 37 | 38 | builder.Property(e => e.ContactName).HasMaxLength(30); 39 | builder.Property(e => e.ContactTitle).HasMaxLength(30); 40 | builder.Property(e => e.Country).HasMaxLength(15); 41 | builder.Property(e => e.Fax).HasMaxLength(24); 42 | builder.Property(e => e.Phone).HasMaxLength(24); 43 | builder.Property(e => e.PostalCode).HasMaxLength(10); 44 | builder.Property(e => e.Region).HasMaxLength(15); 45 | 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/EmployeeTerritoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class EmployeeTerritoriesMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => new { e.EmployeeId, e.TerritoryId }) 14 | .IsClustered(false); 15 | 16 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID"); 17 | 18 | builder.Property(e => e.TerritoryId) 19 | .HasColumnName("TerritoryID") 20 | .HasMaxLength(20); 21 | 22 | builder.HasOne(d => d.Employee) 23 | .WithMany(p => p.EmployeeTerritories) 24 | .HasForeignKey(d => d.EmployeeId) 25 | .OnDelete(DeleteBehavior.ClientSetNull) 26 | .HasConstraintName("FK_EmployeeTerritories_Employees"); 27 | 28 | builder.HasOne(d => d.Territory) 29 | .WithMany(p => p.EmployeeTerritories) 30 | .HasForeignKey(d => d.TerritoryId) 31 | .OnDelete(DeleteBehavior.ClientSetNull) 32 | .HasConstraintName("FK_EmployeeTerritories_Territories"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/EmployeesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class EmployeesMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.EmployeeId); 14 | 15 | builder.HasIndex(e => e.LastName) 16 | .HasDatabaseName("LastName"); 17 | 18 | builder.HasIndex(e => e.PostalCode) 19 | .HasDatabaseName("PostalCode"); 20 | 21 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID") 22 | .ValueGeneratedNever(); 23 | 24 | builder.Property(e => e.Address).HasMaxLength(60); 25 | 26 | builder.Property(e => e.BirthDate).HasColumnType("datetime"); 27 | 28 | builder.Property(e => e.City).HasMaxLength(15); 29 | 30 | builder.Property(e => e.Country).HasMaxLength(15); 31 | 32 | builder.Property(e => e.Extension).HasMaxLength(4); 33 | 34 | builder.Property(e => e.FirstName) 35 | .IsRequired() 36 | .HasMaxLength(10); 37 | 38 | builder.Property(e => e.HireDate).HasColumnType("datetime"); 39 | 40 | builder.Property(e => e.HomePhone).HasMaxLength(24); 41 | 42 | builder.Property(e => e.LastName) 43 | .IsRequired() 44 | .HasMaxLength(20); 45 | 46 | builder.Property(e => e.Notes).HasColumnType("ntext"); 47 | 48 | builder.Property(e => e.Photo).HasColumnType("image"); 49 | 50 | builder.Property(e => e.PhotoPath).HasMaxLength(255); 51 | 52 | builder.Property(e => e.PostalCode).HasMaxLength(10); 53 | 54 | builder.Property(e => e.Region).HasMaxLength(15); 55 | 56 | builder.Property(e => e.Title).HasMaxLength(30); 57 | 58 | builder.Property(e => e.TitleOfCourtesy).HasMaxLength(25); 59 | 60 | builder.HasOne(d => d.ReportsToNavigation) 61 | .WithMany(p => p!.InverseReportsToNavigation) 62 | .HasForeignKey(d => d.ReportsTo) 63 | .HasConstraintName("FK_Employees_Employees"); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/OrderDetailsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class OrderDetailsMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => new { e.OrderId, e.ProductId }); 14 | 15 | builder.ToTable("Order Details"); 16 | 17 | builder.HasIndex(e => e.OrderId) 18 | .HasDatabaseName("OrdersOrder_Details"); 19 | 20 | builder.HasIndex(e => e.ProductId) 21 | .HasDatabaseName("ProductsOrder_Details"); 22 | 23 | builder.Property(e => e.OrderId).HasColumnName("OrderID"); 24 | 25 | builder.Property(e => e.ProductId).HasColumnName("ProductID"); 26 | 27 | builder.Property(e => e.Quantity).HasDefaultValueSql("((1))"); 28 | 29 | builder.Property(e => e.UnitPrice).HasColumnType("money"); 30 | 31 | builder.HasOne(d => d.Order) 32 | .WithMany(p => p.OrderDetails) 33 | .HasForeignKey(d => d.OrderId) 34 | .OnDelete(DeleteBehavior.ClientSetNull) 35 | .HasConstraintName("FK_Order_Details_Orders"); 36 | 37 | builder.HasOne(d => d.Product) 38 | .WithMany(p => p.OrderDetails) 39 | .HasForeignKey(d => d.ProductId) 40 | .OnDelete(DeleteBehavior.ClientSetNull) 41 | .HasConstraintName("FK_Order_Details_Products"); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/OrderMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class OrderMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | 12 | base.Configure(builder); 13 | 14 | builder.HasKey(e => e.OrderId); 15 | 16 | builder.HasIndex(e => e.CustomerId) 17 | .HasDatabaseName("CustomersOrders"); 18 | 19 | builder.HasIndex(e => e.EmployeeId) 20 | .HasDatabaseName("EmployeesOrders"); 21 | 22 | builder.HasIndex(e => e.OrderDate) 23 | .HasDatabaseName("OrderDate"); 24 | 25 | builder.HasIndex(e => e.ShipPostalCode) 26 | .HasDatabaseName("ShipPostalCode"); 27 | 28 | builder.HasIndex(e => e.ShipVia) 29 | .HasDatabaseName("ShippersOrders"); 30 | 31 | builder.HasIndex(e => e.ShippedDate) 32 | .HasDatabaseName("ShippedDate"); 33 | 34 | builder.Property(e => e.OrderId).HasColumnName("OrderID") 35 | .ValueGeneratedNever(); 36 | 37 | builder.Property(e => e.CustomerId) 38 | .HasColumnName("CustomerID") 39 | .HasMaxLength(5); 40 | 41 | builder.Property(e => e.EmployeeId).HasColumnName("EmployeeID"); 42 | 43 | builder.Property(e => e.Freight) 44 | .HasColumnType("money") 45 | .HasDefaultValueSql("((0))"); 46 | 47 | builder.Property(e => e.OrderDate).HasColumnType("datetime"); 48 | 49 | builder.Property(e => e.RequiredDate).HasColumnType("datetime"); 50 | 51 | builder.Property(e => e.ShipAddress).HasMaxLength(60); 52 | 53 | builder.Property(e => e.ShipCity).HasMaxLength(15); 54 | 55 | builder.Property(e => e.ShipCountry).HasMaxLength(15); 56 | 57 | builder.Property(e => e.ShipName).HasMaxLength(40); 58 | 59 | builder.Property(e => e.ShipPostalCode).HasMaxLength(10); 60 | 61 | builder.Property(e => e.ShipRegion).HasMaxLength(15); 62 | 63 | builder.Property(e => e.ShippedDate).HasColumnType("datetime"); 64 | 65 | builder.HasOne(d => d.Customer) 66 | .WithMany(p => p!.Orders) 67 | .HasForeignKey(d => d.CustomerId) 68 | .HasConstraintName("FK_Orders_Customers"); 69 | 70 | builder.HasOne(d => d.Employee) 71 | .WithMany(p => p!.Orders) 72 | .HasForeignKey(d => d.EmployeeId) 73 | .HasConstraintName("FK_Orders_Employees"); 74 | 75 | builder.HasOne(d => d.ShipViaNavigation) 76 | .WithMany(p => p!.Orders) 77 | .HasForeignKey(d => d.ShipVia) 78 | .HasConstraintName("FK_Orders_Shippers"); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/ProductsMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class ProductsMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(e => e.ProductId); 12 | 13 | builder.HasIndex(e => e.CategoryId) 14 | .HasDatabaseName("CategoryID"); 15 | 16 | builder.HasIndex(e => e.ProductName) 17 | .HasDatabaseName("ProductName"); 18 | 19 | builder.HasIndex(e => e.SupplierId) 20 | .HasDatabaseName("SuppliersProducts"); 21 | 22 | builder.Property(e => e.ProductId).HasColumnName("ProductID") 23 | .ValueGeneratedNever(); 24 | 25 | builder.Property(e => e.CategoryId).HasColumnName("CategoryID"); 26 | 27 | builder.Property(e => e.ProductName) 28 | .IsRequired() 29 | .HasMaxLength(40); 30 | 31 | builder.Property(e => e.QuantityPerUnit).HasMaxLength(20); 32 | 33 | builder.Property(e => e.ReorderLevel).HasDefaultValueSql("((0))"); 34 | 35 | builder.Property(e => e.SupplierId).HasColumnName("SupplierID"); 36 | 37 | builder.Property(e => e.UnitPrice) 38 | .HasColumnType("money") 39 | .HasDefaultValueSql("((0))"); 40 | 41 | builder.Property(e => e.UnitsInStock).HasDefaultValueSql("((0))"); 42 | 43 | builder.Property(e => e.UnitsOnOrder).HasDefaultValueSql("((0))"); 44 | 45 | builder.HasOne(d => d.Category) 46 | .WithMany(p => p!.Products) 47 | .HasForeignKey(d => d.CategoryId) 48 | .HasConstraintName("FK_Products_Categories"); 49 | 50 | builder.HasOne(d => d.Supplier) 51 | .WithMany(p => p!.Products) 52 | .HasForeignKey(d => d.SupplierId) 53 | .HasConstraintName("FK_Products_Suppliers"); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/RegionMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class RegionMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.RegionId) 14 | .IsClustered(false); 15 | 16 | builder.Property(e => e.RegionId) 17 | .HasColumnName("RegionID") 18 | .ValueGeneratedNever(); 19 | 20 | builder.Property(e => e.RegionDescription) 21 | .IsRequired() 22 | .HasMaxLength(50); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/ShippersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class ShippersMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.ShipperId); 14 | 15 | builder.Property(e => e.ShipperId).HasColumnName("ShipperID") 16 | .ValueGeneratedNever(); 17 | 18 | builder.Property(e => e.CompanyName) 19 | .IsRequired() 20 | .HasMaxLength(40); 21 | 22 | builder.Property(e => e.Phone).HasMaxLength(24); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/SuppliersMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class SuppliersMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.SupplierId); 14 | 15 | builder.HasIndex(e => e.CompanyName) 16 | .HasDatabaseName("CompanyName"); 17 | 18 | builder.HasIndex(e => e.PostalCode) 19 | .HasDatabaseName("PostalCode"); 20 | 21 | builder.Property(e => e.SupplierId).HasColumnName("SupplierID") 22 | .ValueGeneratedNever(); 23 | 24 | builder.Property(e => e.Address).HasMaxLength(60); 25 | 26 | builder.Property(e => e.City).HasMaxLength(15); 27 | 28 | builder.Property(e => e.CompanyName) 29 | .IsRequired() 30 | .HasMaxLength(40); 31 | 32 | builder.Property(e => e.ContactName).HasMaxLength(30); 33 | 34 | builder.Property(e => e.ContactTitle).HasMaxLength(30); 35 | 36 | builder.Property(e => e.Country).HasMaxLength(15); 37 | 38 | builder.Property(e => e.Fax).HasMaxLength(24); 39 | 40 | builder.Property(e => e.HomePage).HasColumnType("ntext"); 41 | 42 | builder.Property(e => e.Phone).HasMaxLength(24); 43 | 44 | builder.Property(e => e.PostalCode).HasMaxLength(10); 45 | 46 | builder.Property(e => e.Region).HasMaxLength(15); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind.Mapping/TerritoriesMap.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping 6 | { 7 | public class TerritoriesMap : BaseEntityMap 8 | { 9 | public override void Configure(EntityTypeBuilder builder) 10 | { 11 | base.Configure(builder); 12 | 13 | builder.HasKey(e => e.TerritoryId) 14 | .IsClustered(false); 15 | 16 | builder.Property(e => e.TerritoryId) 17 | .HasColumnName("TerritoryID") 18 | .HasMaxLength(20) 19 | .ValueGeneratedNever(); 20 | 21 | builder.Property(e => e.RegionId).HasColumnName("RegionID"); 22 | 23 | builder.Property(e => e.TerritoryDescription) 24 | .IsRequired() 25 | .HasMaxLength(50); 26 | 27 | builder.HasOne(d => d.Region) 28 | .WithMany(p => p.Territories) 29 | .HasForeignKey(d => d.RegionId) 30 | .OnDelete(DeleteBehavior.ClientSetNull) 31 | .HasConstraintName("FK_Territories_Region"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/Models/Northwind/NorthwindContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using LinqToDB.EntityFrameworkCore.BaseTests.Models.Northwind; 4 | using LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind.Mapping; 5 | using LinqToDB.Expressions; 6 | using LinqToDB.Extensions; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Northwind 10 | { 11 | public class NorthwindContext : DbContext 12 | { 13 | public DbSet Categories { get; set; } = null!; 14 | public DbSet CustomerCustomerDemo { get; set; } = null!; 15 | public DbSet CustomerDemographics { get; set; } = null!; 16 | public DbSet Customers { get; set; } = null!; 17 | public DbSet Employees { get; set; } = null!; 18 | public DbSet EmployeeTerritories { get; set; } = null!; 19 | public DbSet OrderDetails { get; set; } = null!; 20 | public DbSet Orders { get; set; } = null!; 21 | public DbSet Products { get; set; } = null!; 22 | public DbSet Region { get; set; } = null!; 23 | public DbSet Shippers { get; set; } = null!; 24 | public DbSet Suppliers { get; set; } = null!; 25 | public DbSet Territories { get; set; } = null!; 26 | 27 | public NorthwindContext(DbContextOptions options) : base(options) 28 | { 29 | 30 | } 31 | 32 | [DbFunction("ProcessLong", "dbo")] 33 | public static int ProcessLong(int seconds) 34 | { 35 | throw new NotImplementedException(); 36 | } 37 | 38 | protected override void OnModelCreating(ModelBuilder modelBuilder) 39 | { 40 | modelBuilder.ApplyConfiguration(new CategoriesMap()); 41 | modelBuilder.ApplyConfiguration(new CustomerCustomerDemoMap()); 42 | modelBuilder.ApplyConfiguration(new CustomerDemographicsMap()); 43 | modelBuilder.ApplyConfiguration(new CustomersMap()); 44 | modelBuilder.ApplyConfiguration(new EmployeesMap()); 45 | modelBuilder.ApplyConfiguration(new EmployeeTerritoriesMap()); 46 | modelBuilder.ApplyConfiguration(new OrderDetailsMap()); 47 | modelBuilder.ApplyConfiguration(new OrderMap()); 48 | modelBuilder.ApplyConfiguration(new ProductsMap()); 49 | modelBuilder.ApplyConfiguration(new RegionMap()); 50 | modelBuilder.ApplyConfiguration(new ShippersMap()); 51 | modelBuilder.ApplyConfiguration(new SuppliersMap()); 52 | modelBuilder.ApplyConfiguration(new TerritoriesMap()); 53 | 54 | modelBuilder.Entity() 55 | .HasQueryFilter(e => !IsFilterProducts || e.ProductId > 2); 56 | 57 | ConfigureGlobalQueryFilters(modelBuilder); 58 | } 59 | 60 | private void ConfigureGlobalQueryFilters(ModelBuilder builder) 61 | { 62 | foreach (var entityType in builder.Model.GetEntityTypes()) 63 | { 64 | if (typeof(ISoftDelete).IsSameOrParentOf(entityType.ClrType)) 65 | { 66 | var method = ConfigureEntityFilterMethodInfo.MakeGenericMethod(entityType.ClrType); 67 | method.Invoke(this, new object[] { builder }); 68 | } 69 | } 70 | } 71 | 72 | private static readonly MethodInfo ConfigureEntityFilterMethodInfo = 73 | MemberHelper.MethodOf(() => ((NorthwindContext)null!).ConfigureEntityFilter(null!)).GetGenericMethodDefinition(); 74 | 75 | public void ConfigureEntityFilter(ModelBuilder builder) 76 | where TEntity: class, ISoftDelete 77 | { 78 | NorthwindContext? obj = null; 79 | 80 | builder.Entity().HasQueryFilter(e => !obj!.IsSoftDeleteFilterEnabled || !e.IsDeleted); 81 | } 82 | 83 | public bool IsFilterProducts { get; set; } 84 | 85 | public bool IsSoftDeleteFilterEnabled { get; set; } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/QueryableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.EntityFrameworkCore.Query; 8 | 9 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests 10 | { 11 | public static class QueryableExtensions 12 | { 13 | public static async Task> FilterExistentAsync(this ICollection items, 14 | IQueryable dbQuery, Expression> prop, CancellationToken cancellationToken = default) 15 | { 16 | var propGetter = prop.Compile(); 17 | var ids = items.Select(propGetter).ToList(); 18 | var parameter = prop.Parameters[0]; 19 | 20 | var predicate = Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(TProp) }, Expression.Constant(ids), prop.Body); 21 | var predicateLambda = Expression.Lambda(predicate, parameter); 22 | 23 | var filtered = Expression.Call(typeof(Queryable), "Where", new[] {typeof(T)}, dbQuery.Expression, 24 | predicateLambda); 25 | 26 | var selectExpr = Expression.Call(typeof(Queryable), "Select", new[] {typeof(T), typeof(TProp)}, filtered, prop); 27 | var selectQuery = dbQuery.Provider.CreateQuery(selectExpr); 28 | 29 | var existingIds = await selectQuery.ToListAsync(cancellationToken); 30 | 31 | return items.Where(i => !existingIds.Contains(propGetter(i))); 32 | } 33 | 34 | public static IIncludableQueryable IncludeInline( 35 | this IIncludableQueryable includable, Expression> inlineProp) 36 | { 37 | var path = new List(); 38 | 39 | var current = includable.Expression; 40 | while (current.NodeType == ExpressionType.Call) 41 | { 42 | var mc = (MethodCallExpression) current; 43 | if (mc.Method.Name == "Include" || mc.Method.Name == "ThenInclude") 44 | path.Add(mc.Arguments[1]); 45 | else 46 | break; 47 | } 48 | 49 | return includable; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/ValueConversion/ConvertorTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using System.Linq; 4 | using LinqToDB.EntityFrameworkCore.BaseTests; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using NUnit.Framework; 8 | 9 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.ValueConversion 10 | { 11 | [TestFixture] 12 | public class ConvertorTests 13 | { 14 | private DbContextOptions _options; 15 | 16 | public class ConvertorContext : DbContext 17 | { 18 | public ConvertorContext(DbContextOptions options) : base(options) 19 | { 20 | } 21 | 22 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 23 | public virtual DbSet Subdivisions { get; set; } = null!; 24 | } 25 | 26 | public ConvertorTests() 27 | { 28 | var optionsBuilder = new DbContextOptionsBuilder(); 29 | 30 | optionsBuilder 31 | .ReplaceService() 32 | .UseSqlServer("Server=.;Database=ConverterTests;Integrated Security=SSPI") 33 | .UseLoggerFactory(TestUtils.LoggerFactory);; 34 | 35 | _options = optionsBuilder.Options; 36 | } 37 | 38 | 39 | [Test] 40 | public void TestToList() 41 | { 42 | using (var ctx = new ConvertorContext(_options)) 43 | using (var db = ctx.CreateLinqToDbConnection()) 44 | { 45 | ctx.Database.EnsureDeleted(); 46 | ctx.Database.EnsureCreated(); 47 | 48 | 49 | var resut = db.InsertWithInt64Identity(new SubDivision() 50 | { Code = "C1", Id = new Id(0), Name = "N1", PermanentId = Guid.NewGuid() }); 51 | 52 | resut = db.InsertWithInt64Identity(new SubDivision() 53 | { Code = "C2", Id = new Id(1), Name = "N2", PermanentId = Guid.NewGuid() }); 54 | 55 | resut = db.InsertWithInt64Identity(new SubDivision() 56 | { Code = "C3", Id = new Id(2), Name = "N3", PermanentId = Guid.NewGuid() }); 57 | 58 | var ef = ctx.Subdivisions.Where(s => s.Id == 1L).ToArray(); 59 | var ltdb = ctx.Subdivisions.ToLinqToDB().Where(s => s.Id == 1L).ToArray(); 60 | 61 | var id = new Nullable>(0L.AsId()); 62 | var ltdb2 = ctx.Subdivisions.ToLinqToDB().Where(s => s.Id == id).ToArray(); 63 | 64 | var ids = new[] {1L.AsId(), 2L.AsId(),}; 65 | var ltdbin = ctx.Subdivisions.ToLinqToDB() 66 | .Where(s => ids.Contains(s.Id)).ToArray(); 67 | 68 | var all = ctx.Subdivisions.ToLinqToDB().ToArray(); 69 | 70 | Assert.AreEqual(ef[0].Code, ltdb[0].Code); 71 | Assert.AreEqual(ef[0].Id, ltdb[0].Id); 72 | 73 | Assert.AreEqual(ef[0].Code, ltdb2[0].Code); 74 | Assert.AreEqual(ef[0].Id, ltdb2[0].Id); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/ValueConversion/IEntity`1.cs: -------------------------------------------------------------------------------- 1 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.ValueConversion 2 | { 3 | public interface IEntity 4 | { 5 | public TKey Id { get; } 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/ValueConversion/IdValueConverterSelector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 5 | 6 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.ValueConversion 7 | { 8 | public sealed class IdValueConverterSelector : ValueConverterSelector 9 | { 10 | public IdValueConverterSelector(ValueConverterSelectorDependencies dependencies) : base(dependencies) 11 | { 12 | } 13 | 14 | public override IEnumerable Select(Type modelClrType, Type? providerClrType = null) 15 | { 16 | var baseConverters = base.Select(modelClrType, providerClrType); 17 | foreach (var converter in baseConverters) 18 | yield return converter; 19 | 20 | modelClrType = Unwrap(modelClrType); 21 | providerClrType = Unwrap(providerClrType); 22 | 23 | if (!modelClrType.IsGenericType) 24 | yield break; 25 | 26 | if (modelClrType.GetGenericTypeDefinition() != typeof(Id<,>)) 27 | yield break; 28 | 29 | var t = modelClrType.GetGenericArguments(); 30 | var key = t[1]; 31 | providerClrType ??= key; 32 | if (key != providerClrType) 33 | yield break; 34 | 35 | var ct = 36 | 37 | key == typeof(long) 38 | ? typeof(IdValueConverter<>).MakeGenericType(t[0]) 39 | : 40 | 41 | typeof(IdValueConverter<,>).MakeGenericType(key, t[0]); 42 | yield return new ValueConverterInfo 43 | ( 44 | modelClrType, 45 | providerClrType, 46 | i => (ValueConverter)Activator.CreateInstance(ct, i.MappingHints)! 47 | ); 48 | 49 | [return: NotNullIfNotNull("type")] 50 | static Type? Unwrap(Type? type) => type == null ? null : Nullable.GetUnderlyingType(type) ?? type; 51 | } 52 | }} 53 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/ValueConversion/IdValueConverter`2.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.ValueConversion 4 | { 5 | public sealed class IdValueConverter : ValueConverter, TKey> 6 | where TEntity : IEntity 7 | where TKey : notnull 8 | { 9 | public IdValueConverter(ConverterMappingHints? mappingHints = null) 10 | : base(id => id.Value, key => new Id(key)) { } 11 | } 12 | 13 | public sealed class IdValueConverter : ValueConverter, long> 14 | where TEntity : IEntity 15 | { 16 | public IdValueConverter(ConverterMappingHints? mappingHints = null) 17 | : base(id => id.Value + 1, key => new Id(key - 1)) { } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/ValueConversion/Id`2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.ValueConversion 5 | { 6 | public static class Id 7 | { 8 | public static Id AsId(this long id) where T : IEntity => id.AsId(); 9 | 10 | public static Id AsId(this Guid guid) where T : IEntity => guid.AsId(); 11 | 12 | public static Id AsId(this TKey @object) 13 | where TEntity : IEntity 14 | where TKey : notnull 15 | => new Id(@object); 16 | } 17 | 18 | public readonly struct Id : IEquatable> where TEntity : IEntity 19 | where TKey: notnull 20 | { 21 | internal Id(TKey id) => Value = id; 22 | internal TKey Value { get; } 23 | public static implicit operator TKey(Id id) => id.Value; 24 | public override string ToString() => $"{typeof(TEntity).Name}({Value})"; 25 | public bool Equals(Id other) => EqualityComparer.Default.Equals(Value, other.Value); 26 | public override bool Equals(object? obj) => obj is Id other && Equals(other); 27 | public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Value); 28 | public static bool operator == (Id left, Id right) 29 | => EqualityComparer.Default.Equals(left.Value, right.Value); 30 | public static bool operator != (Id left, Id right) => !(left == right); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/LinqToDB.EntityFrameworkCore.SqlServer.Tests/ValueConversion/SubDivision.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.ValueConversion 4 | { 5 | public class SubDivision : IEntity 6 | { 7 | long IEntity.Id => Id; 8 | public Id Id { get; set; } 9 | public Guid PermanentId { get; set; } 10 | public string Code { get; set; } = null!; 11 | public string Name { get; set; } = null!; 12 | public bool? IsDeleted { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | solution: 'linq2db.EFCore.sln' 3 | build_configuration: 'Release' 4 | assemblyVersion: 5.1.6 5 | nugetVersion: 5.1.6 6 | artifact_nugets: 'nugets' 7 | 8 | # build on commits to important branches (master + release branches): 9 | trigger: 10 | - master 11 | - release 12 | # don't trigger pr builds by default, users should trigger them manually using /azp bot commands 13 | # when we have multiple test runs waiting for free job, when nobody needs them 14 | # we only want to trigger it for pr to release branch 15 | pr: 16 | - master 17 | 18 | stages: 19 | 20 | ############################# 21 | # Build and publish nugets # 22 | ############################# 23 | - stage: '' 24 | displayName: '' 25 | jobs: 26 | - job: build_job 27 | pool: 28 | vmImage: 'windows-2019' 29 | variables: 30 | packageVersion: $(nugetVersion) 31 | displayName: 'Build' 32 | 33 | steps: 34 | 35 | - task: PowerShell@2 36 | inputs: 37 | filePath: '$(Build.SourcesDirectory)/Build/SetVersion.ps1' 38 | workingDirectory: '$(Build.SourcesDirectory)' 39 | arguments: -path $(Build.SourcesDirectory)/Build/linq2db.Default.props -version $(assemblyVersion) 40 | displayName: Update assembly version 41 | 42 | - task: MSBuild@1 43 | inputs: 44 | solution: '$(solution)' 45 | configuration: '$(build_configuration)' 46 | msbuildArguments: '/t:Restore;Rebuild -m' 47 | displayName: Build Solution 48 | 49 | - powershell: echo "##vso[task.setvariable variable=packageVersion]$(packageVersion)-rc.$(Build.BuildId)" 50 | condition: ne(variables['Build.SourceBranchName'], 'release') 51 | displayName: Set nuget RC version for non-release branch 52 | 53 | - task: PowerShell@2 54 | inputs: 55 | filePath: '$(Build.SourcesDirectory)/NuGet/BuildNuspecs.ps1' 56 | workingDirectory: '$(Build.SourcesDirectory)' 57 | arguments: -path $(Build.SourcesDirectory)/NuGet/linq2db.EntityFrameworkCore.nuspec -version $(packageVersion) -branch $(Build.SourceBranchName) 58 | displayName: Generate nuspec 59 | 60 | - task: NuGetToolInstaller@0 61 | inputs: 62 | versionSpec: '5.x' 63 | workingDirectory: $(Build.SourcesDirectory)/NuGet 64 | displayName: Install nuget 65 | 66 | - task: CmdLine@2 67 | inputs: 68 | script: 'nuget Pack linq2db.EntityFrameworkCore.nuspec -OutputDirectory built' 69 | workingDirectory: $(Build.SourcesDirectory)/NuGet 70 | displayName: Build nuget 71 | 72 | - task: PublishBuildArtifacts@1 73 | inputs: 74 | pathToPublish: '$(Build.SourcesDirectory)/NuGet/built' 75 | artifactName: '$(artifact_nugets)' 76 | displayName: Publish nugets to artifacts 77 | 78 | - task: NuGetCommand@2 79 | inputs: 80 | command: 'push' 81 | packagesToPush: '$(Build.SourcesDirectory)/NuGet/built/linq2db.EntityFrameworkCore.*.nupkg' 82 | nuGetFeedType: 'internal' 83 | publishVstsFeed: '0dcc414b-ea54-451e-a54f-d63f05367c4b/967a4107-9788-41a4-9f6d-a2318aab1410' 84 | displayName: Publish to Azure Artifacts feed 85 | condition: and(succeeded(), eq(variables['Build.SourceBranchName'], 'master')) 86 | 87 | - task: NuGetCommand@2 88 | inputs: 89 | command: 'push' 90 | packagesToPush: '$(Build.SourcesDirectory)/NuGet/built/linq2db.EntityFrameworkCore.*.nupkg' 91 | nuGetFeedType: 'external' 92 | publishFeedCredentials: 'linq2db nuget.org feed' 93 | displayName: Publish to Nuget.org 94 | condition: and(succeeded(), eq(variables['Build.SourceBranchName'], 'release')) 95 | -------------------------------------------------------------------------------- /linq2db.EFCore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29324.140 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "linq2db.EntityFrameworkCore", "Source\LinqToDB.EntityFrameworkCore\linq2db.EntityFrameworkCore.csproj", "{29F45BE9-3B57-4162-A02A-59F05528A0E7}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{A3F30061-485E-4112-9675-3AE332BEED13}" 9 | ProjectSection(SolutionItems) = preProject 10 | azure-pipelines.yml = azure-pipelines.yml 11 | Build\linq2db.Default.props = Build\linq2db.Default.props 12 | Build\linq2db.snk = Build\linq2db.snk 13 | Build\linq2db.Tests.props = Build\linq2db.Tests.props 14 | Build\SetVersion.ps1 = Build\SetVersion.ps1 15 | EndProjectSection 16 | EndProject 17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7316BE20-8825-4234-923D-45F0FBC48B7D}" 18 | ProjectSection(SolutionItems) = preProject 19 | NuGet.config = NuGet.config 20 | README.md = README.md 21 | EndProjectSection 22 | EndProject 23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{4BCDB6FB-E23E-4908-8C7A-F40A336D4B7D}" 24 | ProjectSection(SolutionItems) = preProject 25 | NuGet\BuildNuspecs.ps1 = NuGet\BuildNuspecs.ps1 26 | NuGet\icon.png = NuGet\icon.png 27 | NuGet\linq2db.EntityFrameworkCore.nuspec = NuGet\linq2db.EntityFrameworkCore.nuspec 28 | EndProjectSection 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinqToDB.EntityFrameworkCore.BaseTests", "Tests\LinqToDB.EntityFrameworkCore.BaseTests\LinqToDB.EntityFrameworkCore.BaseTests.csproj", "{71CBC83D-C406-4EB3-8AFC-88C0ECA9C0E8}" 31 | EndProject 32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinqToDB.EntityFrameworkCore.SqlServer.Tests", "Tests\LinqToDB.EntityFrameworkCore.SqlServer.Tests\LinqToDB.EntityFrameworkCore.SqlServer.Tests.csproj", "{C8883CDC-DB45-4D5D-A573-3D14BDC8AF85}" 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinqToDB.EntityFrameworkCore.PostgreSQL.Tests", "Tests\LinqToDB.EntityFrameworkCore.PostgreSQL.Tests\LinqToDB.EntityFrameworkCore.PostgreSQL.Tests.csproj", "{F65A1BBB-46F4-48A4-9778-1A5396A876AE}" 35 | EndProject 36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinqToDB.EntityFrameworkCore.PomeloMySql.Tests", "Tests\LinqToDB.EntityFrameworkCore.PomeloMySql.Tests\LinqToDB.EntityFrameworkCore.PomeloMySql.Tests.csproj", "{0F013A9A-AC97-4A5E-A5D7-E1B64541CC46}" 37 | EndProject 38 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinqToDB.EntityFrameworkCore.SQLite.Tests", "Tests\LinqToDB.EntityFrameworkCore.SQLite.Tests\LinqToDB.EntityFrameworkCore.SQLite.Tests.csproj", "{615C5697-5FA7-490C-8812-3D61994A8AC1}" 39 | EndProject 40 | Global 41 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 42 | Debug|Any CPU = Debug|Any CPU 43 | Release|Any CPU = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 46 | {29F45BE9-3B57-4162-A02A-59F05528A0E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {29F45BE9-3B57-4162-A02A-59F05528A0E7}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {29F45BE9-3B57-4162-A02A-59F05528A0E7}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {29F45BE9-3B57-4162-A02A-59F05528A0E7}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {71CBC83D-C406-4EB3-8AFC-88C0ECA9C0E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {71CBC83D-C406-4EB3-8AFC-88C0ECA9C0E8}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {71CBC83D-C406-4EB3-8AFC-88C0ECA9C0E8}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {71CBC83D-C406-4EB3-8AFC-88C0ECA9C0E8}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {C8883CDC-DB45-4D5D-A573-3D14BDC8AF85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {C8883CDC-DB45-4D5D-A573-3D14BDC8AF85}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {C8883CDC-DB45-4D5D-A573-3D14BDC8AF85}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {C8883CDC-DB45-4D5D-A573-3D14BDC8AF85}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {F65A1BBB-46F4-48A4-9778-1A5396A876AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {F65A1BBB-46F4-48A4-9778-1A5396A876AE}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {F65A1BBB-46F4-48A4-9778-1A5396A876AE}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {F65A1BBB-46F4-48A4-9778-1A5396A876AE}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {0F013A9A-AC97-4A5E-A5D7-E1B64541CC46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {0F013A9A-AC97-4A5E-A5D7-E1B64541CC46}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {0F013A9A-AC97-4A5E-A5D7-E1B64541CC46}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {0F013A9A-AC97-4A5E-A5D7-E1B64541CC46}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {615C5697-5FA7-490C-8812-3D61994A8AC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {615C5697-5FA7-490C-8812-3D61994A8AC1}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {615C5697-5FA7-490C-8812-3D61994A8AC1}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {615C5697-5FA7-490C-8812-3D61994A8AC1}.Release|Any CPU.Build.0 = Release|Any CPU 70 | EndGlobalSection 71 | GlobalSection(SolutionProperties) = preSolution 72 | HideSolutionNode = FALSE 73 | EndGlobalSection 74 | GlobalSection(ExtensibilityGlobals) = postSolution 75 | SolutionGuid = {96E250D9-36FF-46EA-980A-4F8D1F88D51F} 76 | EndGlobalSection 77 | EndGlobal 78 | -------------------------------------------------------------------------------- /linq2db.EFCore.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | DB 3 | EF --------------------------------------------------------------------------------