{"id":22065789,"url":"https://github.com/karenpayneoregon/efcore-dapper-dataprovider","last_synced_at":"2026-05-06T05:34:23.246Z","repository":{"id":110840534,"uuid":"606222974","full_name":"karenpayneoregon/efcore-dapper-dataprovider","owner":"karenpayneoregon","description":"Basic code samples for working with sql-server via EF Core, Dapper and SqlClient","archived":false,"fork":false,"pushed_at":"2023-02-25T08:46:41.000Z","size":1651,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-29T00:29:41.375Z","etag":null,"topics":["csharp-core","dapper-donet-core","efcore7","sqlclient","sqlserver"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/karenpayneoregon.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-24T22:06:27.000Z","updated_at":"2024-06-11T18:39:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"26ca34e7-0432-477d-aa07-2cd8f339e816","html_url":"https://github.com/karenpayneoregon/efcore-dapper-dataprovider","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fefcore-dapper-dataprovider","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fefcore-dapper-dataprovider/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fefcore-dapper-dataprovider/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fefcore-dapper-dataprovider/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karenpayneoregon","download_url":"https://codeload.github.com/karenpayneoregon/efcore-dapper-dataprovider/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245144978,"owners_count":20568056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp-core","dapper-donet-core","efcore7","sqlclient","sqlserver"],"created_at":"2024-11-30T19:22:00.410Z","updated_at":"2026-05-06T05:34:23.201Z","avatar_url":"https://github.com/karenpayneoregon.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Working with EF Core/Dapper/SqlClient basics\n\nLearn how to read and insert images into a SQL-Server database using [Dapper](https://www.learndapper.com/), [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/) and [SqlClient](https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient?view=dotnet-plat-ext-7.0) data provider.\n\nFor novice and even intermediate level developers working with images can be a daunting task simple because they either write code expecting it to immediately work with no regards to things like using the proper data types or copying pasting code from the Internet without changing much and expect the code to work.\n\nTo reach the main audiences three different approaches are used Dapper, EF Core and SqlClient data provider.  \n\n## Using the proper data type\n\nThe developer with no experience with working with images will select Image verses varbinary(max) not realizing Image type most likely will be removed in future versions of SQL-Server. This means, do not use Image, instead use varbinary(max).\n\n## Column definition for code samples\n\n![table definition](assets/TableDefinition.png)\n\n## Operations\n\nThe three methods used will both insert and read a single record.\n\nWhat is important to know:\n\n- Dapper and EF Core require less hand written code\n- Dapper and SqlClient require decent knowledge of SQL syntax\n- EF Core, in this case were configured using [EF Power Tools](https://dev.to/karenpayneoregon/ef-power-tools-tutorial-44d8) which means no manual configuration.\n- Which to use is a personal choice\n\n## Insert new record version 1\n\nIn the following samples a record is inserted but we do not get the new record key\n\n### Insert new record with SqlClient data provider \n\nTo insert a new record.\n\n- Create a connection object with a connection string\n- Create a command object\n- Add a single parameter\n- Open the connection\n- Execute the command\n\n```csharp\npublic static void InsertImage(byte[] imageBytes)\n{\n    var sql = \"INSERT INTO [dbo].[Pictures1] ([Photo])  VALUES (@ByteArray)\";\n\n    using var cn = new SqlConnection(ConnectionString());\n    using var cmd = new SqlCommand(sql, cn);\n\n    cmd.Parameters.Add(\"@ByteArray\", SqlDbType.VarBinary).Value = imageBytes;\n\n    cn.Open();\n    cmd.ExecuteNonQuery();\n}\n```\n\n### Insert new record with Dapper\n\n- Create a connection object with a connection string\n- Add a single parameter\n- Execute the command\n\n```csharp\npublic static void InsertImage(byte[] imageBytes)\n{\n\n    var sql = \"INSERT INTO [dbo].[Pictures1] ([Photo])  VALUES (@ByteArray)\";\n\n    using var cn = new SqlConnection(ConnectionString());\n    var parameters = new { ByteArray = imageBytes};\n    cn.Execute(sql, parameters);\n\n}\n```\n\n### Insert new record with Dapper\n\n- Create an instance of the DbContext\n- Create an instance of the type \n- Save changes\n\n```csharp\npublic static void InsertImage(byte[] imageBytes)\n{\n\n    using var context = new Context();\n    context.Add(new Pictures() { Photo = imageBytes });\n    context.SaveChanges();\n\n}\n```\n\n## Insert new record version 2\n\nIn the following samples a record is inserted with the new record primary key\n\n### SqlClient\n\nWe append `SELECT CAST(scope_identity() AS int)` to the insert and rather than `ExecuteNonQuery` use `ExecuteScalar` which returns an object, we cast to the same type as the primary key.\n\n```csharp\npublic static void InsertImage(byte[] imageBytes)\n{\n    var sql = \n        \"\"\"\n        INSERT INTO [dbo].[Pictures1] ([Photo])  VALUES (@ByteArray);\n        SELECT CAST(scope_identity() AS int);\n        \"\"\";\n\n    using var cn = new SqlConnection(ConnectionString());\n    using var cmd = new SqlCommand(sql, cn);\n\n    cmd.Parameters.Add(\"@ByteArray\", SqlDbType.VarBinary).Value = imageBytes;\n\n    cn.Open();\n    var key = (int)cmd.ExecuteScalar();\n}\n```\n\n### Dapper\n\nThe following `OUTPUT Inserted.Id` is added to the SQL, note `Id` needs to match the primary key name.\n\nRather then `Execute` method we use `ExecuteScalar` which is basically the same as SqlClient.\n\n```csharp\npublic static void InsertImage(byte[] imageBytes)\n{\n\n    var sql = \"INSERT INTO [dbo].[Pictures1] ([Photo]) OUTPUT Inserted.Id VALUES (@ByteArray)  \";\n\n    using var cn = new SqlConnection(ConnectionString());\n    var parameters = new { ByteArray = imageBytes};\n    var key = (int)cn.ExecuteScalar(sql, parameters);\n\n}\n```\n\n### EF Core\n\nSimply move the Pictures object to a variable. After SaveChanges, `photoContainer.Id` will have the new primary key.\n\n\n```csharp\npublic static void InsertImage(byte[] imageBytes)\n{\n\n    using var context = new Context();\n\n    var photoContainer = new Pictures() { Photo = imageBytes };\n    context.Add(photoContainer);\n    context.SaveChanges();\n\n}\n```\n\n## Read an image\n\nWhat you will notice is that between the three methods, they are practically the same.\n\nWith EF Core there are a few extra lines to keep in sync with the return type to matach the other two methods.\n\nThe SqlClient has several more lines of code than the other two methods.\n\n\n**SqlClient**\n\n```csharp\npublic static (PhotoContainer container, bool success) ReadImage(int identifier)\n{\n    var photoContainer = new PhotoContainer() { Id = identifier };\n    var sql = \"SELECT id, Photo FROM dbo.Pictures1 WHERE dbo.Pictures1.id = @id;\";\n\n    using var cn = new SqlConnection(ConnectionString());\n    using var cmd = new SqlCommand(sql, cn);\n\n    cmd.Parameters.Add(\"@Id\", SqlDbType.Int).Value = identifier;\n\n    cn.Open();\n\n    var reader = cmd.ExecuteReader();\n    reader.Read();\n\n    if (!reader.HasRows)\n    {\n        return (null, false);\n    }\n\n    var imageData = (byte[])reader[1];\n    using (var ms = new MemoryStream(imageData, 0, imageData.Length))\n    {\n        ms.Write(imageData, 0, imageData.Length);\n        photoContainer.Picture = Image.FromStream(ms, true);\n    }\n\n    return (photoContainer, true);\n}\n```\n\n**Dapper**\n\n```csharp\npublic static (PhotoContainer container, bool success) ReadImage(int identifier)\n{\n\n    var photoContainer = new PhotoContainer() { Id = identifier };\n    var sql = \"SELECT id, Photo FROM dbo.Pictures1 WHERE dbo.Pictures1.id = @id\";\n\n    using var cn = new SqlConnection(ConnectionString());\n    var parameters = new { id = identifier };\n    var container = cn.QueryFirstOrDefault\u003cImageContainer\u003e(sql, parameters);\n\n    if (container is null)\n    {\n        return (null, false);\n    }\n\n    var imageData = container.Photo;\n\n    using (var ms = new MemoryStream(imageData, 0, imageData.Length))\n    {\n        ms.Write(imageData, 0, imageData.Length);\n        photoContainer.Picture = Image.FromStream(ms, true);\n    }\n\n    return (photoContainer, true);\n}\n```\n\n**EF Core**\n\n```csharp\npublic static (PhotoContainer container, bool success) ReadImage(int identifier)\n{\n    var photoContainer = new PhotoContainer() { Id = identifier };\n    using var context = new Context();\n\n    var item = context.Pictures1.FirstOrDefault(item =\u003e item.Id == identifier);\n\n    if (item is null)\n    {\n        return (null, false);\n    }\n\n    var imageData = item.Photo;\n\n    using (var ms = new MemoryStream(imageData, 0, imageData.Length))\n    {\n        ms.Write(imageData, 0, imageData.Length);\n        photoContainer.Picture = Image.FromStream(ms, true);\n    }\n\n    return (photoContainer, true);\n\n}\n```\n\n## Special note\n\n\u003e **Note**\n\u003e There is no exception handling in any of the code as the code was written properly, this does not by any means to not implement exception handling in your code as many things can go wrong, so implement exception handling\n\n## Preparing the project to run\n\nUsing the script under the folder Scripts, create the database, create the single table and populate.\n\n## Why you a Windows Forms project?\n\nWell the code had been done in an ASP.NET Core, Blazor, MAUI or unit test while using a Windows Forms project bypasses things such as securty issues and is very easy to read and understand.\n\n\n## Source code\n\nClone the following [GitHub repository](https://github.com/karenpayneoregon/efcore-dapper-dataprovider)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarenpayneoregon%2Fefcore-dapper-dataprovider","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarenpayneoregon%2Fefcore-dapper-dataprovider","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarenpayneoregon%2Fefcore-dapper-dataprovider/lists"}