{"id":22065573,"url":"https://github.com/karenpayneoregon/sql-server-images","last_synced_at":"2026-03-03T03:02:58.983Z","repository":{"id":195976172,"uuid":"628698400","full_name":"karenpayneoregon/sql-server-images","owner":"karenpayneoregon","description":"Working with images for SQL-Server basics","archived":false,"fork":false,"pushed_at":"2024-06-23T12:06:44.000Z","size":2234,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-24T04:45:13.302Z","etag":null,"topics":["csharp-core","images","sqlserver"],"latest_commit_sha":null,"homepage":"https://dev.to/karenpayneoregon/sql-server-working-with-images-dp3","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-04-16T18:43:50.000Z","updated_at":"2024-06-23T12:06:47.000Z","dependencies_parsed_at":"2023-09-20T21:28:38.352Z","dependency_job_id":"921c764f-b47a-47da-b643-77c0a54d2483","html_url":"https://github.com/karenpayneoregon/sql-server-images","commit_stats":null,"previous_names":["karenpayneoregon/sql-server-images"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/karenpayneoregon/sql-server-images","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fsql-server-images","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fsql-server-images/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fsql-server-images/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fsql-server-images/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karenpayneoregon","download_url":"https://codeload.github.com/karenpayneoregon/sql-server-images/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karenpayneoregon%2Fsql-server-images/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30030839,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T00:31:48.536Z","status":"online","status_checked_at":"2026-03-03T02:00:07.650Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","images","sqlserver"],"created_at":"2024-11-30T19:19:36.564Z","updated_at":"2026-03-03T03:02:58.939Z","avatar_url":"https://github.com/karenpayneoregon.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Introduction\n\nLearn how to store images in a SQL-Server database table where the image size is no greater than 256k and 1M as the rule of thumb is for images over 1M it is best to store those images in the file system. Another piece of advice, separate images from factual information e.g. an employee table should not contain the employee image, instead store the image in an image table which relates back to the employee table.\n\n## Requires\n\nMicrosoft Visual Studio 2022 or greater, for Visual Studio 2022 edition needs to be 17.4.x as code provided uses various new features of .NET Core 7.\n\n![Figure2](assets/Figure2.png)\n\n\n## Recommendations\n\nUse [SSMS](https://learn.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver16) for working with SQL-Server outside of Visual Studio while Visual Studio provides tools needed, SSMS is easier.\n\n## Data type for images\n\nMany developers use **image** which works but Microsoft has indicated that future versions of SQL-Server will be removing **image** type, see [Microsoft docs](https://learn.microsoft.com/en-us/sql/t-sql/data-types/ntext-text-and-image-transact-sql?redirectedfrom=MSDN\u0026view=sql-server-ver16). For this reason, what follows will use [varbinary(MAX)](https://learn.microsoft.com/en-us/sql/t-sql/data-types/binary-and-varbinary-transact-sql?view=sql-server-ver16).\n\n## Overview of code sample\n\nCode presented is in a conventional Windows Forms, .NET Core 7 with the location of images below the application folder. \n\nWhy not use a dialog to get the image files? Any developer with a little knowledge of working with Windows Forms should know how to use a dialog to collect files and introducing a dialog clouds the intent to work with images.\n\n### Classes\n\n- FileOperations, a simple class with one method, get the image files to insert into a table.\n- PhotoOperations\n    - **InsertImage** method to insert a new record\n    - **ReadImage** read record by primary key\n    - **Read** read all records\n    - **TruncateTable** for resetting the table\n\n### Form operations\n\nIn form shown event\n- Reset the table for storing images\n- Get image files from disk\n- Insert images from above into the database table\n- Immediately read images back into a list\n- Assign the list to a ComboBox\n- Setup the SelectedIndexChanged event for the ComboBox for displaying the current image in a PictureBox\n\n### Read back a single image\n\nThere are two buttons, one attempts to read an non-existing image while the other reads back an existing image.\n\nWhy show attempting to read a non-existing image? Simply because it's a best practice to use assertion as what might happening during the course of running an application an external entity remove the record? Best to be pro-active.\n\n```csharp\npublic static (PhotoContainer, bool) ReadImage(int identifier)\n{\n    PhotoContainer photoContainer = new() { Id = identifier };\n\n    var sql = \n        \"\"\"\n            SELECT \n                id, \n                Photo,\n                Description\n            FROM \n                dbo.Pictures1 \n            WHERE \n                dbo.Pictures1.id = @id;\n        \"\"\";\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\n    if (reader.HasRows)\n    {\n        reader.Read();\n\n        photoContainer.Description = reader.GetString(2);\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    else\n    {\n        return (photoContainer, false);\n    }\n    \n}\n```\n\n## Code to insert an image\n\nNote the return value **return cmd.ExecuteNonQuery();** is not used here but in a production application one should check that 1 is returned and even add a try-catch in the event of failure e.g. insufficient permissions, database offline etc. \n\n```csharp\npublic static int InsertImage(byte[] imageBytes, string description)\n{\n    var sql = \n        \"\"\"\n            INSERT INTO [dbo].[Pictures1] \n                (\n                    [Photo], \n                    Description\n                ) \n            VALUES \n            (\n                @ByteArray, \n                @Description\n            )\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    cmd.Parameters.Add(\"@Description\", SqlDbType.NVarChar).Value = description;\n\n    cn.Open();\n\n    return cmd.ExecuteNonQuery();\n```\n\n\n## DataTable container\n\nTypically a novice developer gravitates to a DataTable as it is easy but these containers are overkill so in the code provided a class/model is used.\n\n```csharp\npublic class PhotoContainer\n{\n    public int Id { get; set; }\n    public Image Picture { get; set; }\n    public string Description { get; set; }\n    public override string ToString() =\u003e Description;\n}\n```\n\u003e **Note**\n\u003e By overriding ToString this will be used for DisplayMember of the ComboBox.\n\n## Preparation to run the code\n\nUsing SSMS create a new database named WorkingImages, run the following in a new query window.\n\n```sql\nUSE [WorkingImages]\nGO\n/****** Object:  Table [dbo].[Pictures1]    Script Date: 4/16/2023 10:13:48 AM ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[Pictures1](\n\t[Id] [int] IDENTITY(1,1) NOT NULL,\n\t[Photo] [varbinary](max) NULL,\n\t[Description] [nvarchar](max) NULL,\n CONSTRAINT [PK_Pictures1] PRIMARY KEY CLUSTERED \n(\n\t[Id] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n```\n\nThe above query is also stored in the project under DataScripts folder.\n\nOpen the solution in Microsoft Visual Studio 2022 with edition 17.4.x which is required for some of the newer features like raw string literals.\n\nBuild the project followed by running the project. On an average machine the insert of images, reading back images and displaying the form will be less than one second.\n\nExpected when the form is displayed.\n\n![Figure1](assets/Figure1.png)\n\n## Accessibility\n\nEach form control has accessibility properties set, its always wise to consider visually impaired users of your application.\n\n## Source code\n\nClone the following [GitHub repository](https://github.com/karenpayneoregon/sql-server-images)\n\n## NuGet packages\n\n- [ConfigurationLibrary](https://www.nuget.org/packages/ConfigurationLibrary/1.0.1?_src=template) This library provides a method to obtain a connection string from appsettings.json to use with a data provider or Entity Framework Core, intended for desktop applications as ASP.NET Core has this already with more options via dependency injection.\n- [Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/5.1.1?_src=template) Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS)\n\n\n## Article location\n\nhttps://dev.to/karenpayneoregon/sql-server-working-with-images-dp3\n\n\n \n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarenpayneoregon%2Fsql-server-images","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarenpayneoregon%2Fsql-server-images","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarenpayneoregon%2Fsql-server-images/lists"}