├── .gitattributes ├── .gitignore ├── EntityFrameworkCoreWithDapper.sln ├── EntityFrameworkCoreWithDapper ├── Controllers │ ├── CreateProductModel.cs │ ├── CreateProductResultModel.cs │ ├── ProductModel.cs │ └── ProductsController.cs ├── Database │ ├── ApiDbContext.cs │ ├── DapperDbContextExtensions.cs │ ├── DapperEFCoreCommand.cs │ ├── PriceHistoryEntity.cs │ └── ProductEntity.cs ├── EntityFrameworkCoreWithDapper.csproj ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── appsettings.Development.json └── appsettings.json ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | 244 | AssemblyInfoBase.cs 245 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30717.126 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreWithDapper", "EntityFrameworkCoreWithDapper\EntityFrameworkCoreWithDapper.csproj", "{0DE83AD3-5B88-4B4A-AE41-D53BBE93BE29}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {0DE83AD3-5B88-4B4A-AE41-D53BBE93BE29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {0DE83AD3-5B88-4B4A-AE41-D53BBE93BE29}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {0DE83AD3-5B88-4B4A-AE41-D53BBE93BE29}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {0DE83AD3-5B88-4B4A-AE41-D53BBE93BE29}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {F6F990F4-B553-43C9-B189-4FC5733AD8DB} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Controllers/CreateProductModel.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCoreWithDapper.Controllers 2 | { 3 | public class CreateProductModel 4 | { 5 | public string Code { get; set; } 6 | public string Name { get; set; } 7 | public decimal Price { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Controllers/CreateProductResultModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EntityFrameworkCoreWithDapper.Controllers 4 | { 5 | public class CreateProductResultModel 6 | { 7 | public Guid Id { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Controllers/ProductModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EntityFrameworkCoreWithDapper.Controllers 4 | { 5 | public class ProductModel 6 | { 7 | public Guid Id { get; set; } 8 | public string Code { get; set; } 9 | public string Name { get; set; } 10 | public decimal Price { get; set; } 11 | public DateTime PriceChangedOn { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Controllers/ProductsController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using EntityFrameworkCoreWithDapper.Database; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace EntityFrameworkCoreWithDapper.Controllers 9 | { 10 | [Route("products")] 11 | public class ProductsController : ControllerBase 12 | { 13 | private readonly ApiDbContext _context; 14 | 15 | public ProductsController(ApiDbContext context) 16 | { 17 | _context = context; 18 | } 19 | 20 | [HttpGet] 21 | public async Task> GetAllAsync([FromQuery] int? skip, [FromQuery] int? take, CancellationToken ct) 22 | { 23 | return await _context.QueryAsync(ct, @" 24 | SELECT p.ExternalId as Id, p.Code, p.Name, lph.Price, lph.CreatedOn as PriceChangedOn 25 | FROM ( 26 | SELECT Id, ExternalId, Code, Name, RowId 27 | FROM Product 28 | ORDER BY Code DESC 29 | LIMIT @Take OFFSET @Skip 30 | ) p 31 | INNER JOIN ( 32 | SELECT ph.ProductId, ph.Price, ph.CreatedOn 33 | FROM PriceHistory ph 34 | INNER JOIN ( 35 | SELECT MAX(RowId) RowId 36 | FROM PriceHistory 37 | GROUP BY ProductId 38 | ) phLatest ON ph.RowId = phLatest.RowId 39 | ) lph ON p.Id = lph.ProductId", new 40 | { 41 | Skip = skip ?? 0, 42 | Take = take ?? 20 43 | }); 44 | } 45 | 46 | [HttpPost] 47 | public async Task CreateAsync([FromBody] CreateProductModel model, CancellationToken ct) 48 | { 49 | var externalId = Guid.NewGuid(); 50 | 51 | await using var tx = await _context.Database.BeginTransactionAsync(ct); 52 | 53 | await _context.ExecuteAsync(ct, @" 54 | INSERT INTO Product (ExternalId, Code, Name) 55 | VALUES (@ExternalId, @Code, @Name); 56 | 57 | INSERT INTO PriceHistory (Price, CreatedOn, ProductId) 58 | SELECT @Price, @CreatedOn, Id 59 | FROM Product 60 | WHERE 61 | rowid = last_insert_rowid();", new 62 | { 63 | ExternalId = externalId, 64 | model.Code, 65 | model.Name, 66 | model.Price, 67 | CreatedOn = DateTime.UtcNow 68 | }); 69 | 70 | await tx.CommitAsync(ct); 71 | 72 | return new CreateProductResultModel 73 | { 74 | Id = externalId 75 | }; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Database/ApiDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace EntityFrameworkCoreWithDapper.Database 4 | { 5 | public class ApiDbContext : DbContext 6 | { 7 | public ApiDbContext(DbContextOptions options) : base(options) 8 | { 9 | 10 | } 11 | 12 | protected override void OnModelCreating(ModelBuilder builder) 13 | { 14 | base.OnModelCreating(builder); 15 | 16 | builder.Entity(cfg => 17 | { 18 | cfg.ToTable("Product"); 19 | 20 | cfg.HasKey(e => e.Id); 21 | cfg.HasAlternateKey(e => e.ExternalId); 22 | 23 | cfg.HasIndex(e => e.Code).IsUnique(); 24 | 25 | cfg.Property(e => e.Id) 26 | .IsRequired() 27 | .ValueGeneratedOnAdd(); 28 | cfg.Property(e => e.ExternalId) 29 | .IsRequired(); 30 | cfg.Property(e => e.Code) 31 | .IsRequired() 32 | .HasMaxLength(8); 33 | cfg.Property(e => e.Name) 34 | .IsRequired() 35 | .HasMaxLength(128); 36 | }); 37 | 38 | builder.Entity(cfg => 39 | { 40 | cfg.ToTable("PriceHistory"); 41 | 42 | cfg.HasKey(e => e.Id); 43 | 44 | cfg.HasIndex(e => e.CreatedOn); 45 | 46 | cfg.Property(e => e.Id) 47 | .IsRequired() 48 | .ValueGeneratedOnAdd(); 49 | cfg.HasOne(e => e.Product) 50 | .WithMany(p => p.PricesHistory) 51 | .IsRequired(); 52 | cfg.Property(e => e.Price) 53 | .IsRequired(); 54 | cfg.Property(e => e.CreatedOn) 55 | .IsRequired(); 56 | }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Database/DapperDbContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Dapper; 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace EntityFrameworkCoreWithDapper.Database 9 | { 10 | public static class DapperDbContextExtensions 11 | { 12 | public static async Task> QueryAsync( 13 | this DbContext context, 14 | CancellationToken ct, 15 | string text, 16 | object parameters = null, 17 | int? timeout = null, 18 | CommandType? type = null 19 | ) 20 | { 21 | using var command = new DapperEFCoreCommand( 22 | context, 23 | text, 24 | parameters, 25 | timeout, 26 | type, 27 | ct 28 | ); 29 | 30 | var connection = context.Database.GetDbConnection(); 31 | return await connection.QueryAsync(command.Definition); 32 | } 33 | 34 | public static async Task ExecuteAsync( 35 | this DbContext context, 36 | CancellationToken ct, 37 | string text, 38 | object parameters = null, 39 | int? timeout = null, 40 | CommandType? type = null 41 | ) 42 | { 43 | using var command = new DapperEFCoreCommand( 44 | context, 45 | text, 46 | parameters, 47 | timeout, 48 | type, 49 | ct 50 | ); 51 | 52 | var connection = context.Database.GetDbConnection(); 53 | return await connection.ExecuteAsync(command.Definition); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Database/DapperEFCoreCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Threading; 4 | using Dapper; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore.Infrastructure; 7 | using Microsoft.EntityFrameworkCore.Storage; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace EntityFrameworkCoreWithDapper.Database 11 | { 12 | public readonly struct DapperEFCoreCommand : IDisposable 13 | { 14 | private readonly ILogger _logger; 15 | 16 | public DapperEFCoreCommand( 17 | DbContext context, 18 | string text, 19 | object parameters, 20 | int? timeout, 21 | CommandType? type, 22 | CancellationToken ct 23 | ) 24 | { 25 | _logger = context.GetService>(); 26 | 27 | var transaction = context.Database.CurrentTransaction?.GetDbTransaction(); 28 | var commandType = type ?? CommandType.Text; 29 | var commandTimeout = timeout ?? context.Database.GetCommandTimeout() ?? 30; 30 | 31 | Definition = new CommandDefinition( 32 | text, 33 | parameters, 34 | transaction, 35 | commandTimeout, 36 | commandType, 37 | cancellationToken: ct 38 | ); 39 | 40 | if (_logger.IsEnabled(LogLevel.Debug)) 41 | { 42 | _logger.LogDebug( 43 | @"Executing DbCommand [CommandType='{commandType}', CommandTimeout='{commandTimeout}'] 44 | {commandText}", Definition.CommandType, Definition.CommandTimeout, Definition.CommandText); 45 | } 46 | } 47 | 48 | public CommandDefinition Definition { get; } 49 | 50 | public void Dispose() 51 | { 52 | if (_logger.IsEnabled(LogLevel.Information)) 53 | { 54 | _logger.LogInformation( 55 | @"Executed DbCommand [CommandType='{commandType}', CommandTimeout='{commandTimeout}'] 56 | {commandText}", Definition.CommandType, Definition.CommandTimeout, Definition.CommandText); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Database/PriceHistoryEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EntityFrameworkCoreWithDapper.Database 4 | { 5 | public class PriceHistoryEntity 6 | { 7 | public long Id { get; set; } 8 | public virtual ProductEntity Product { get; set; } 9 | public decimal Price { get; set; } 10 | public DateTime CreatedOn { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Database/ProductEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace EntityFrameworkCoreWithDapper.Database 5 | { 6 | public class ProductEntity 7 | { 8 | public long Id { get; set; } 9 | public Guid ExternalId { get; set; } 10 | public string Code { get; set; } 11 | public string Name { get; set; } 12 | public virtual ICollection PricesHistory { get; set; } 13 | 14 | public ProductEntity() 15 | { 16 | PricesHistory = new HashSet(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/EntityFrameworkCoreWithDapper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace EntityFrameworkCoreWithDapper 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:61168", 7 | "sslPort": 44310 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "EntityFrameworkCoreWithDapper": { 19 | "commandName": "Project", 20 | "dotnetRunMessages": "true", 21 | "launchBrowser": true, 22 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using Dapper; 4 | using EntityFrameworkCoreWithDapper.Database; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.Data.Sqlite; 7 | using Microsoft.EntityFrameworkCore; 8 | using Microsoft.Extensions.DependencyInjection; 9 | 10 | namespace EntityFrameworkCoreWithDapper 11 | { 12 | public class Startup 13 | { 14 | private const string ConnectionString = "Data Source=EntityFrameworkCoreWithDapper;Mode=Memory;Cache=Shared"; 15 | private static SqliteConnection _keepAliveConnection; 16 | 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | SqlMapper.AddTypeHandler(new GuidTypeHandler()); 20 | 21 | services.AddDbContext(o => 22 | { 23 | o.UseSqlite(ConnectionString); 24 | }); 25 | 26 | services.AddMvc(); 27 | 28 | services.AddSwaggerGen(); 29 | } 30 | 31 | public void Configure(IApplicationBuilder app) 32 | { 33 | _keepAliveConnection = new SqliteConnection(ConnectionString); 34 | _keepAliveConnection.Open(); 35 | 36 | using (var scope = app.ApplicationServices.GetRequiredService().CreateScope()) 37 | { 38 | var ctx = scope.ServiceProvider.GetRequiredService(); 39 | ctx.Database.EnsureCreated(); 40 | } 41 | 42 | app.UseDeveloperExceptionPage(); 43 | 44 | app.UseSwagger(); 45 | 46 | app.UseSwaggerUI(c => 47 | { 48 | c.SwaggerEndpoint("/swagger/v1/swagger.json", "EF Core with Dapper Example Api V1"); 49 | }); 50 | 51 | app.UseRouting(); 52 | 53 | app.UseEndpoints(endpoints => 54 | { 55 | endpoints.MapControllers(); 56 | }); 57 | } 58 | 59 | private class GuidTypeHandler : SqlMapper.TypeHandler 60 | { 61 | public override void SetValue(IDbDataParameter parameter, Guid value) => parameter.Value = value; 62 | 63 | public override Guid Parse(object value) => Guid.Parse((string) value); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Trace", 5 | "Microsoft": "Debug", 6 | "Microsoft.Hosting.Lifetime": "Debug" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /EntityFrameworkCoreWithDapper/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 João Simões 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EntityFrameworkCoreWithDapper 2 | Example project integrating [Dapper](https://github.com/StackExchange/Dapper) with [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) without the need for `TransactionScope`. 3 | 4 | Buy Me A Coffee 5 | 6 | ## Articles 7 | 8 | * [Integrating Dapper with Entity Framework Core](https://joaoprsimoes.medium.com/integrating-dapper-with-entity-framework-core-55aacc94b5b0) 9 | --------------------------------------------------------------------------------