{"id":25072706,"url":"https://github.com/0username/simple.dbextensions.tvp","last_synced_at":"2025-06-15T10:34:32.176Z","repository":{"id":275858823,"uuid":"927267904","full_name":"0UserName/Simple.DbExtensions.Tvp","owner":"0UserName","description":null,"archived":false,"fork":false,"pushed_at":"2025-05-13T19:46:18.000Z","size":20,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-13T20:58:38.333Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/0UserName.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,"zenodo":null}},"created_at":"2025-02-04T17:21:12.000Z","updated_at":"2025-05-13T19:46:22.000Z","dependencies_parsed_at":"2025-03-31T17:48:03.583Z","dependency_job_id":"89327057-52ad-4b30-af10-9afe32db467a","html_url":"https://github.com/0UserName/Simple.DbExtensions.Tvp","commit_stats":null,"previous_names":["0username/simple.dbextensions.tvp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/0UserName/Simple.DbExtensions.Tvp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0UserName%2FSimple.DbExtensions.Tvp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0UserName%2FSimple.DbExtensions.Tvp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0UserName%2FSimple.DbExtensions.Tvp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0UserName%2FSimple.DbExtensions.Tvp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0UserName","download_url":"https://codeload.github.com/0UserName/Simple.DbExtensions.Tvp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0UserName%2FSimple.DbExtensions.Tvp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259960545,"owners_count":22938083,"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":[],"created_at":"2025-02-06T22:33:18.148Z","updated_at":"2025-06-15T10:34:32.162Z","avatar_url":"https://github.com/0UserName.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿![Release workflow](https://github.com/0UserName/Simple.DbExtensions.Tvp/actions/workflows/release.yml/badge.svg)\n\n\n\n# Motivation\n\nThe motivation for developing the library is to simplify the creation of `DataTable` instances used as table-valued parameters when interacting with stored procedures, as well as to add a number of additional features, including pooling, schema and data validation, and column trimming.\n\n\n\n# Usage\n\nAdd a dependency on this package and create a class implementing `ITableValued`, using the built-in `AbstractTableValued` implementation or your own. Once this is done, you can create a `DataTable` based on your class definitions:\n\n\n```csharp\n[TableValued(nameof(Row))]\npublic class Row : AbstractTableValued\u003cRow\u003e\n```\n\n\n```csharp\nRow[] rows = new\nRow[]\n{\n    new Row(),\n    new Row(),\n    new Row()\n};\n\nusing (PooledDataTableScope\u003cRow\u003e scope = rows.BuildScope())\n{\n    Upload(scope.Table);\n}\n```\n\n\nOr\n\n\n```csharp\nPooledDataTable table = rows.Build();\n\nUpload(table);\n\ntable.Return\u003cRow\u003e();\n```\n\n\nOr\n\n\n```csharp\nPooledDataTable table = new Row().Build();\n\nUpload(table);\n\ntable.Return\u003cRow\u003e();\n```\n\n\nIf you are using [Dapper](https://github.com/DapperLib/Dapper), add:\n\n\n```csharp\nSqlMapper.AddTypeMap(typeof(PooledDataTable), DbType.Object);\n```\n\n\n\n## Pooling\n\nPooling is applied at each stage of creating a `DataTable` (but not for `DataRow`). Each type has its own pool, which has a fixed size of 50. If needed, a different configuration can be specified:\n\n\n```csharp\n[TableValuedPool(10)]\npublic class Row : AbstractTableValued\u003cRow\u003e\n```\n\n\n\n## Metadata\n\nIn the simplest case, to create a `DataTable`, only information about the columns is needed: name, type, and ordinal. By default, this information is retrieved using reflection. Everything is presented in a static form, except for `Ordinal`, which can be overridden:\n\n\n```csharp\n[TableValued(nameof(Row))]\npublic class Row : AbstractTableValued\u003cRow\u003e\n{\n    [Ordinal(1)]\n    public int Property0\n\n    [Ordinal(0)]\n    public int Property1\n}\n```\n\n\nHowever, it is also possible to load custom metadata from a database, which have a higher priority:\n\n\n```csharp\nMetadataStorage.AddColumns(nameof(Row), new IColumnExternalMetadata[]\n{\n    new ColumnExternalMetadata(table: nameof(Row), name: nameof(Row.Property0), type: typeof(int).FullName, ordinal: 1, allowDBNull: default, maxLength: -1, unique: default),\n    new ColumnExternalMetadata(table: nameof(Row), name: nameof(Row.Property1), type: typeof(int).FullName, ordinal: 0, allowDBNull: default, maxLength: -1, unique: default)\n});\n```\n\n\n`AllowDBNull`, `MaxLength`, and `Unique` are built-in constraints that are checked after all rows have been loaded into the `DataTable`. If any of these constraints are violated, a `ConstraintException` or `NoNullAllowedException` will be thrown.\n\n\n\u003e **NOTE**: If a property is not part of a table-valued parameter, it will be discarded. However, when the structure in the database is changed after the metadata has been loaded, it is assumed that the user application follow to the [Fail-fast](https://en.wikipedia.org/wiki/Fail-fast_system) approach, since updating the metadata at runtime is not possible — only at startup.\n\n\n\u003e **NOTE**: SQL script that loads metadata from the database is not included in the delivery, as no DBA would allow executing it from a third-party library due to security concerns.\n\n\n\nReferences: [AllowDBNull](https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.allowdbnull) / [MaxLength](https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.maxlength) / [Ordinal](https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.ordinal) / [Unique](https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.unique) / [ConstraintException](https://learn.microsoft.com/ru-ru/dotnet/api/system.data.constraintexception) / [NoNullAllowedException](https://learn.microsoft.com/ru-ru/dotnet/api/system.data.nonullallowedexception)\n\n\n\n# Related projects\n\n- [npgsql.tvp](https://github.com/0UserName/npgsql.tvp)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0username%2Fsimple.dbextensions.tvp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0username%2Fsimple.dbextensions.tvp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0username%2Fsimple.dbextensions.tvp/lists"}