{"id":21654624,"url":"https://github.com/kros-sk/kros.korm.msaccess","last_synced_at":"2025-08-19T04:40:18.085Z","repository":{"id":48666871,"uuid":"177142728","full_name":"Kros-sk/Kros.KORM.MsAccess","owner":"Kros-sk","description":"Simple and fast micro-ORM framework for .NET with Microsoft Access Database.","archived":false,"fork":false,"pushed_at":"2024-01-16T19:27:11.000Z","size":501,"stargazers_count":3,"open_issues_count":6,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-07T22:45:24.078Z","etag":null,"topics":["dot-net","dotnet","ms-access","msaccess","orm","orm-library"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kros-sk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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":"2019-03-22T13:13:23.000Z","updated_at":"2024-10-10T04:14:30.000Z","dependencies_parsed_at":"2025-01-25T06:33:08.601Z","dependency_job_id":null,"html_url":"https://github.com/Kros-sk/Kros.KORM.MsAccess","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kros-sk%2FKros.KORM.MsAccess","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kros-sk%2FKros.KORM.MsAccess/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kros-sk%2FKros.KORM.MsAccess/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kros-sk%2FKros.KORM.MsAccess/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kros-sk","download_url":"https://codeload.github.com/Kros-sk/Kros.KORM.MsAccess/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252967974,"owners_count":21833245,"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":["dot-net","dotnet","ms-access","msaccess","orm","orm-library"],"created_at":"2024-11-25T08:28:28.158Z","updated_at":"2025-05-07T22:45:31.060Z","avatar_url":"https://github.com/Kros-sk.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kros.KORM.MsAccess [![Build Status](https://dev.azure.com/krossk/DevShared/_apis/build/status/Kros.KORM/Kros.KORM.MsAccess?branchName=features/build)](https://dev.azure.com/krossk/DevShared/_build/latest?definitionId=67\u0026branchName=master)\n\nKros.KORM is simple, fast and easy to use micro-ORM framework for .NETStandard created by Kros a.s. from Slovakia.\n\n## Why to use Kros.KORM\n\n* You can easily create query builder for creating queries returning IEnumerable of your POCO objects\n* Linq support\n* Saving changes to your data (Insert / Update / Delete)\n* Kros.KORM supports bulk operations for fast inserting and updating large amounts of data (BulkInsert, BulkDelete)\n\n## Documentation\n\nFor configuration, general information and examples [see the documentation](https://kros-sk.github.io/docs/Kros.KORM.MsAccess/).\n\n### Download\n\nKros.KORM is available from __Nuget__ [__Kros.KORM.MsAccess__](https://www.nuget.org/packages/Kros.KORM.MsAccess/).\n\n## Contributing Guide\n\nTo contribute with new topics/information or make changes, see [contributing](https://github.com/Kros-sk/Kros.KORM.MsAccess/blob/master/CONTRIBUTING.md) for instructions and guidelines.\n\n## This topic contains following sections\n\n* [Query](#query)\n* [Linq to Kros.KORM](#linq-to-kroskorm)\n* [DataAnnotation attributes](#dataannotation-attributes)\n* [Convention model mapper](#convention-model-mapper)\n* [Converters](#converters)\n* [OnAfterMaterialize](#onaftermaterialize)\n* [Property injection](#property-injection)\n* [Model builder](#model-builder)\n* [Committing of changes](#committing-of-changes)\n* [SQL commands executing](#sql-commands-executing)\n* [Logging](#logging)\n* [Supported database types](#supported-database-types)\n* [ASP.NET Core extensions](#aspnet-core-extensions)\n* [Unit and performance tests](#unit-and-performance-tests)\n\n### Query\n\nYou can use Kros.KORM for creating queries and their materialization. Kros.KORM helps you put together desired query, that can return instances of objects populated from database by using foreach or linq.\n\n#### Query for obtaining data\n\n```c#\nvar people = database.Query\u003cPerson\u003e()\n    .Select(\"p.Id\", \"FirstName\", \"LastName\", \"PostCode\")\n    .From(\"Person JOIN Address ON (Person.AddressId = Address.Id)\")\n    .Where(\"Age \u003e @1\", 18);\n\nforeach (var person in people)\n{\n    Console.WriteLine(person.FirstName);\n}\n```\n\nFor more information take a look at definition of [IQuery](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM.Query.IQuery-1.html).\n\n### Linq to Kros.KORM\n\nKros.KORM allows you to use Linq for creating queries. Basic queries are translated to SQL language.\n\n#### Example\n\n```c#\nvar people = database.Query\u003cPerson\u003e()\n    .From(\"Person JOIN Address ON (Person.AddressId = Address.Id)\")\n    .Where(p =\u003e p.LastName.EndsWith(\"ová\"))\n    .OrderByDescending(p =\u003e p.Id)\n    .Take(5);\n\nforeach (var person in people)\n{\n    Console.WriteLine(person.FirstName);\n}\n```\n\nSupported Linq methods are ```Where, FirstOrDefault, Take, Sum, Max, Min, OrderBy, OrderByDescending, ThenBy, ThenByDescending, Count, Any, Skip.```\n\nOther methods, such as ```Select, GroupBy, Join``` are not supported at this moment because of their complexity.\n\nYou can use also some string functions in Linq queries:\n\n| String function | Example                                               | Translation to T-SQL                          |\n| --------------- | ----------------------------------------------------- | --------------------------------------------- |\n| StartWith       | Where(p =\u003e p.FirstName.StartWith(\"Mi\"))               | WHERE (FirstName LIKE @1 + '%')               |\n| EndWith         | Where(p =\u003e p.LastName.EndWith(\"ová\"))                 | WHERE (LastName LIKE '%' + @1)                |\n| Contains        | Where(p =\u003e p.LastName.Contains(\"ia\"))                 | WHERE (LastName LIKE '%' + @1 + '%')          |\n| IsNullOrEmpty   | Where(p =\u003e String.IsNullOrEmpty(p.LastName))          | WHERE (LastName IS NULL OR LastName = '')     |\n| ToUpper         | Where(p =\u003e p.LastName.ToUpper() == \"Smith\")           | WHERE (UPPER(LastName) = @1)                  |\n| ToLower         | Where(p =\u003e p.LastName.ToLower() == \"Smith\")           | WHERE (LOWER(LastName) = @1)                  |\n| Replace         | Where(p =\u003e p.FirstName.Replace(\"hn\", \"zo\") == \"Jozo\") | WHERE (REPLACE(FirstName, @1, @2) = @3)       |\n| Substring       | Where(p =\u003e p.FirstName.Substring(1, 2) == \"oh\")       | WHERE (SUBSTRING(FirstName, @1 + 1, @2) = @3) |\n| Trim            | Where(p =\u003e p.FirstName.Trim() == \"John\")              | WHERE (RTRIM(LTRIM(FirstName)) = @1)          |\n\nTranslation is provided by implementation of [ISqlExpressionVisitor](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM.Query.Sql.ISqlExpressionVisitor.html).\n\n### DataAnnotation attributes\n\nProperties (not readonly or writeonly properties) are implicitly mapped to database fields with same name. When you want to map property to database field with different name use AliasAttribute. The same works for mapping POCO classes with database tables.\n\n```c#\n[Alias(\"Workers\")]\nprivate class Staff\n{\n    [Alias(\"PK\")]\n    public int Id { get; set; }\n\n    [Alias(\"Name\")]\n    public string FirstName { get; set; }\n\n    [Alias(\"SecondName\")]\n    public string LastName { get; set; }\n}\n\nprivate void StaffExample()\n{\n    using (var database = new Database(_connection))\n    {\n        _command.CommandText = \"SELECT PK, Name, SecondName from Workers\";\n\n        using (var reader = _command.ExecuteReader())\n        {\n            var staff = database.ModelBuilder.Materialize\u003cStaff\u003e(reader);\n        }\n    }\n}\n```\n\nWhen you need to have read-write properties independent of the database use `NoMapAttribute`.\n\n```c#\n[NoMap]\npublic int Computed { get; set; }\n```\n\n### Convention model mapper\n\nIf you have different conventions for naming properties in POCO classes and fields in database, you can redefine behaviour of ModelMapper, which serves mapping POCO classes to database tables and vice versa.\n\n#### Redefining mapping conventions example\n\n```c#\nDatabase.DefaultModelMapper.MapColumnName = (colInfo, modelType) =\u003e\n{\n    return string.Format(\"COL_{0}\", colInfo.PropertyInfo.Name.ToUpper());\n};\n\nDatabase.DefaultModelMapper.MapTableName = (tInfo, type) =\u003e\n{\n    return string.Format(\"TABLE_{0}\", type.Name.ToUpper());\n};\n\nusing (var database = new Database(_connection))\n{\n\n    _command.CommandText = \"SELECT COL_ID, COL_FIRSTNAME from TABLE_WORKERS\";\n\n    using (var reader = _command.ExecuteReader())\n    {\n        var people = database.ModelBuilder.Materialize\u003cPerson\u003e(reader);\n\n        foreach (var person in people)\n        {\n            Console.WriteLine(person.FirstName);\n        }\n    }\n}\n```\n\nAlternatively you can write your own implementation of [IModelMapper](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM.Metadata.IModelMapper.html).\n\n##### Custom model mapper\n\n```c#\nDatabase.DefaultModelMapper = new CustomModelMapper();\n```\n\nIf your POCO class is defined in external library, you can redefine mapper, so it can map properties of the model to desired database names.\n\n##### External class mapping example\n\n```c#\nvar externalPersonMap = new Dictionary\u003cstring, string\u003e() {\n    { nameOf(ExternalPerson.oId), \"Id\" },\n    { nameOf(ExternalPerson.Name), \"FirstName\" },\n    { nameOf(ExternalPerson.SecondName), \"LastName\" }\n};\n\nDatabase.DefaultModelMapper.MapColumnName = (colInfo, modelType) =\u003e\n{\n    if (modelType == typeof(ExternalPerson))\n    {\n        return externalPersonMap[colInfo.PropertyInfo.Name];\n    }\n    else\n    {\n        return colInfo.PropertyInfo.Name;\n    }\n};\n\nusing (var database = new Database(_connection))\n{\n    var people = database.Query\u003cExternalPerson\u003e();\n\n    foreach (var person in people)\n    {\n        Console.WriteLine($\"{person.oId} : {person.Name}-{person.SecondName}\");\n    }\n}\n```\n\nFor dynamic mapping you can use method [SetColumnName\u003cTModel, TValue\u003e](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM.Metadata.IModelMapper.html#Kros_KORM_Metadata_IModelMapper_SetColumnName__2_System_Linq_Expressions_Expression_System_Func___0___1___System_String_)\n\n```c#\nDatabase.DefaultModelMapper.SetColumnName\u003cPerson, string\u003e(p =\u003e p.Name, \"FirstName\");\n```\n\n### Converters\n\nData type of column in database and data type of property in your POCO class may differ. Some of these differences are automatically solved by Kros.KORM, for example `double` in database is converted to `int` in your model, same as `int` in database to `enum` in model, etc.\n\nFor more complicated conversion Kros.KORM offers possibility similar to data binding in WPF, where `IValueConverter` is used.\n\nImagine you store a list of addresses separated by some special character (for example #) in one long text column, but the property in your POCO class is list of strings.\n\nLet's define a converter that can convert string to list of strings.\n\n```c#\npublic class AddressesConverter : IConverter\n{\n    public object Convert(object value)\n    {\n        var ret = new List\u003cstring\u003e();\n        if (value != null)\n        {\n            var address = value.ToString();\n            var addresses = address.Split('#');\n\n            ret.AddRange(addresses);\n        }\n\n        return ret;\n    }\n\n    public object ConvertBack(object value)\n    {\n        var addresses = string.Join(\"#\", (value as List\u003cstring\u003e));\n\n        return addresses;\n    }\n}\n```\n\nAnd now you can set this converter for your property.\n\n```c#\n[Converter(typeof(AddressesConverter))]\npublic List\u003cstring\u003e Addresses { get; set; }\n```\n\n### OnAfterMaterialize\n\nIf you want to do some special action right after materialisation is done (for example to do some calculations) or you want to get some other values from source reader, that can not by processed automatically, your class should implement interface [IMaterialize](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM.Materializer.IMaterialize.html).\n\nYou can do whatever you need in method ```OnAfterMaterialize```.\n\nFor example, if you have three int columns for date in database (Year, Month and Day) but in your POCO class you have only one date property, you can solve it as follows:\n\n```c#\n[NoMap]\npublic DateTime Date { get; set; }\n\npublic void OnAfterMaterialize(IDataRecord source)\n{\n    var year = source.GetInt32(source.GetOrdinal(\"Year\"));\n    var month = source.GetInt32(source.GetOrdinal(\"Month\"));\n    var day = source.GetInt32(source.GetOrdinal(\"Day\"));\n\n    this.Date = new DateTime(year, month, day);\n}\n```\n\n### Property injection\n\nSometimes you might need to inject some service to your model, for example calculator or logger. For these purposes Kros.KORM offers `IInjectionConfigurator`, that can help you with injection configuration.\n\nLet's have properties in model\n\n```c#\n[NoMap]\npublic ICalculationService CalculationService { get; set; }\n\n[NoMap]\npublic ILogger Logger { get; set; }\n```\n\nAnd that is how you can configure them.\n\n```c#\nDatabase.DefaultModelMapper\n    .InjectionConfigurator\u003cPerson\u003e()\n        .FillProperty(p =\u003e p.CalculationService, () =\u003e new CalculationService())\n        .FillProperty(p =\u003e p.Logger, () =\u003e ServiceContainer.Instance.Resolve\u003cILogger\u003e());\n```\n\n### Model builder\n\nFor materialisation Kros.KORM uses `IModelFactory`, that creates factory for creating and filling your POCO objects.\n\nBy default `DynamicMethodModelFactory` is implemented, which uses dynamic method for creating delegates.\n\nIf you want to try some other implementation (for example based on reflexion) you can redefine property `Database.DefaultModelFactory`.\n\n```c#\nDatabase.DefaultModelFactory = new ReflectionModelfactory();\n```\n\n### Committing of changes\n\nYou can use Kros.KORM also for editing, adding or deleting records from database. [IdDbSet](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.Query.IDbSet-1.html) is designed for that.\n\nRecords to edit or delete are identified by the primary key. You can set primary key to your POCO class by using `Key` attribute.\n\n```c#\n[Key()]\npublic int Id { get; set; }\n\npublic string FirstName { get; set; }\n\npublic string LastName { get; set; }\n```\n\n#### Inserting records to database\n\n```c#\npublic void Insert()\n{\n    using (var database = new Database(_connection))\n    {\n        var people = database.Query\u003cPerson\u003e().AsDbSet();\n\n        people.Add(new Person() { Id = 1, FirstName = \"Jean Claude\", LastName = \"Van Damme\" });\n        people.Add(new Person() { Id = 2, FirstName = \"Sylvester\", LastName = \"Stallone\" });\n\n        people.CommitChanges();\n    }\n}\n```\n\nKros.KORM supports bulk inserting, which is one of its best features. You add records to DbSet standardly by method ```Add```, but for committing to database use method ```BulkInsert``` instead of ```CommitChanges```.\n\n```c#\nvar people = database.Query\u003cPerson\u003e().AsDbSet();\n\nforeach (var person in dataForImport)\n{\n    people.Add(person);\n}\n\npeople.BulkInsert();\n```\n\nKros.KORM supports also bulk update of records, you can use ```BulkUpdate``` method.\n\n```c#\nvar people = database.Query\u003cPerson\u003e().AsDbSet();\n\nforeach (var person in dataForUpdate)\n{\n    people.Edit(person);\n}\n\npeople.BulkUpdate();\n```\n\nThis bulk way of inserting or updating data is several times faster than standard inserts or updates.\n\nFor both of bulk operations you can provide data as an argument of method. The advantage is that if you have a specific enumerator, you do not need to spill data into memory.\n\n#### Primary key generating\n\nKros.KORM supports generating of primary keys for inserted records. Primary key must be simple `Int32` column. Primary key property in POCO class must be decorated by `Key` attribute and its property `AutoIncrementMethodType` must be set to `Custom`.\n\n```c#\n[Key(autoIncrementMethodType: AutoIncrementMethodType.Custom)]\npublic int Id { get; set; }\n```\n\nKros.KORM generates primary key for every inserted record, that does not have value for primary key property. For generating primary keys implementations of [IIdGenerator](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.Utils/Kros.Data.IIdGenerator.html) are used.\n\n#### Editing records in database\n\n```c#\npublic void Edit()\n{\n    using (var database = new Database(_connection))\n    {\n        var people = database.Query\u003cPerson\u003e().AsDbSet();\n\n        foreach (var person in people)\n        {\n            person.LastName += \"ová\";\n            people.Edit(person);\n        }\n\n        people.CommitChanges();\n    }\n}\n```\n\n### Deleting records from database\n\n```c#\npublic void Delete()\n{\n    using (var database = new Database(_connection))\n    {\n        var people = database.Query\u003cPerson\u003e().AsDbSet();\n\n        people.Delete(people.FirstOrDefault(x =\u003e x.Id == 1));\n        people.Delete(people.FirstOrDefault(x =\u003e x.Id == 2));\n\n        people.CommitChanges();\n    }\n}\n```\n\n#### Explicit transactions\n\nBy default, changes of a `DbSet` are committed to database in a transaction. If committing of one record fails, rollback of transaction is executed.\n\nSometimes you might come to situation, when such implicit transaction would not meet your requirements. For example you need to commit changes to two tables as an atomic operation. When saving changes to first of tables is not successful, you want to discard changes to the other table. Solution of that task is easy with explicit transactions supported by Kros.KORM. See the documentation of [BeginTransaction](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.IDatabase.html#Kros_KORM_IDatabase_BeginTransaction).\n\n```c#\nusing (var transaction = database.BeginTransaction())\n{\n    var invoicesDbSet = database.Query\u003cInvoice\u003e().AsDbSet();\n    var itemsDbSet = database.Query\u003cItem\u003e().AsDbSet();\n\n    try\n    {\n        invoicesDbSet.Add(invoices);\n        invoicesDbSet.CommitChanges();\n\n        itemsDbSet.Add(items);\n        itemsDbSet.CommitChanges();\n\n        transaction.Commit();\n    }\n    catch\n    {\n        transaction.Rollback();\n    }\n}\n```\n\n### SQL commands executing\n\nKros.KORM supports SQL commands execution. There are three types of commands:\n\n* ```ExecuteNonQuery``` for commands that do not return value (DELETE, UPDATE, ...)\n* ```ExecuteScalar``` for commands that return only one value (SELECT)\n* ```ExecuteStoredProcedure``` for executing of stored procedures. Stored procedure may return scalar value or list of values or it can return data in output parameters.\n\n#### Execution of stored procedure example\n\n```c#\npublic class Person\n{\n    public int Id { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n    public DateTime BDay { get; set; }\n}\n\nprivate Database _database = new Database(new SqlConnection(\"connection string\"));\n\n// Stored procedure returns a scalar value.\nint intResult = _database.ExecuteStoredProcedure\u003cint\u003e(\"ProcedureName\");\nDateTime dateResult = _database.ExecuteStoredProcedure\u003cDateTime\u003e(\"ProcedureName\");\n\n// Stored procedure sets the value of output parameter.\nvar parameters = new CommandParameterCollection();\nparameters.Add(\"@param1\", 10);\nparameters.Add(\"@param2\", DateTime.Now);\nparameters.Add(\"@outputParam\", null, DbType.String, ParameterDirection.Output);\n\n_database.ExecuteStoredProcedure\u003cstring\u003e(\"ProcedureName\", parameters);\n\nConsole.WriteLine(parameters[\"@outputParam\"].Value);\n\n\n// Stored procedure returns complex object.\nPerson person = _database.ExecuteStoredProcedure\u003cPerson\u003e(\"ProcedureName\");\n\n\n// Stored procedure returns list of complex objects.\nIEnumerable\u003cPerson\u003e persons = _database.ExecuteStoredProcedure\u003cIEnumerable\u003cPerson\u003e\u003e(\"ProcedureName\");\n```\n\n#### CommandTimeout support\n\nIf you want to execute time-consuming command, you will definitely appreciate `CommandTimeout` property of transaction. See the documentation of [BeginTransaction](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.IDatabase.html#Kros_KORM_IDatabase_BeginTransaction).\n\nWarning: You can set `CommandTimeout` only for main transaction, not for nested transactions. In that case CommandTimout of main transaction will be used.\n\n```c#\nIEnumerable\u003cPerson\u003e persons = null;\n\nusing (var transaction = database.BeginTransaction(IsolationLevel.Chaos))\n{\n    transaction.CommandTimeout = 150;\n\n    try\n    {\n        persons = database.ExecuteStoredProcedure\u003cIEnumerable\u003cPerson\u003e\u003e(\"LongRunningProcedure_GetPersons\");\n        transaction.Commit();\n    }\n    catch\n    {\n        transaction.Rollback();\n    }\n}\n```\n\n### Logging\n\nKros.KORM offers the ability to log each generated and executed query. All you have to do is add this line to your source code.\n\n```c#\nDatabase.Log = Console.WriteLine;\n```\n\n### Supported database types\n\nKros.KORM uses its own [QueryProvider](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.Query.QueryProvider.html) to execute query in a database. [ISqlExpressionVisitor](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.Query.Sql.ISqlExpressionVisitor.html) transforms IQuery to SELECT command specific for each supported database engine.\n\nMsAccess is suported from version 2.4 in Kros.KORM.MsAccess library. If you need to work with MS Access database, you have to refer this library in your project and register [MsAccessQueryProviderFactory](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM.MsAccess/Kros.KORM.Query.MsAccess.MsAccessQueryProviderFactory.html).\n\n```c#\nMsAccessQueryProviderFactory.Register();\n```\n\nCurrent version of Kros.KORM suports databases MS ACCESS and MS SQL.\n\nIf you want to support a different database engine, you can implement your own [IQueryProvider](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.Query.IQueryProvider.html). And register it in [QueryProviderFactories](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.KORM/Kros.KORM.Query.QueryProviderFactories.html).\n\n```c#\npublic class CustomQueryProvider : QueryProvider\n{\n    public CustomQueryProvider(ConnectionStringSettings connectionString,\n       ISqlExpressionVisitor sqlGenerator,\n       IModelBuilder modelBuilder,\n       ILogger logger)\n        : base(connectionString, sqlGenerator, modelBuilder, logger)\n    {\n    }\n\n    public CustomQueryProvider(DbConnection connection,\n        ISqlExpressionVisitor sqlGenerator,\n        IModelBuilder modelBuilder,\n        ILogger logger)\n            : base(connection, sqlGenerator, modelBuilder, logger)\n    {\n    }\n\n    public override DbProviderFactory DbProviderFactory =\u003e CustomDbProviderFactory.Instance;\n\n    public override IBulkInsert CreateBulkInsert()\n    {\n        if (IsExternalConnection)\n        {\n            return new CustomBulkInsert(Connection as CustomConnection);\n        }\n        else\n        {\n            return new CustomBulkInsert(ConnectionString);\n        }\n    }\n\n    public override IBulkUpdate CreateBulkUpdate()\n    {\n        if (IsExternalConnection)\n        {\n            return new CustomBulkUpdate(Connection as CustomConnection);\n        }\n        else\n        {\n            return new CustomBulkUpdate(ConnectionString);\n        }\n    }\n\n    protected override IDatabaseSchemaLoader GetSchemaLoader()\n    {\n        throw new NotImplementedException();\n    }\n}\n\npublic class CustomQuerySqlGenerator : DefaultQuerySqlGenerator\n{\n    public CustomQuerySqlGenerator(IDatabaseMapper databaseMapper)\n        : base(databaseMapper)\n    { }\n}\n\n\npublic class CustomQueryProviderFactory : IQueryProviderFactory\n{\n    public Query.IQueryProvider Create(DbConnection connection, IModelBuilder modelBuilder, IDatabaseMapper databaseMapper) =\u003e\n        new CustomQueryProvider(connection, new CustomQuerySqlGenerator(databaseMapper), modelBuilder, new Logger());\n\n    public Query.IQueryProvider Create(ConnectionStringSettings connectionString, IModelBuilder modelBuilder, IDatabaseMapper databaseMapper) =\u003e\n        new CustomQueryProvider(connectionString, new CustomQuerySqlGenerator(databaseMapper), modelBuilder, new Logger());\n\n    public static void Register()\n    {\n        QueryProviderFactories.Register\u003cCustomConnection\u003e(\"System.Data.CustomDb\", new CustomQueryProviderFactory());\n    }\n}\n```\n\n### ASP.NET Core extensions\nFor simple integration into ASP.NET Core projects, the [__Kros.KORM.Extensions.Asp__](https://www.nuget.org/packages/Kros.KORM.Extensions.Asp/) package was created.\n\nYou can use the `AddKorm` extension method to register `IDatabase` to the DI container.\n\n```\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddKorm(Configuration);\n}\n```\n\nThe configuration file *(typically `appsettings.json`)* must contain a section `ConnectionString`.\n```\n  \"ConnectionString\": {\n    \"ProviderName\": \"System.Data.SqlClient\",\n    \"ConnectionString\": \"Server=servername\\\\instancename;Initial Catalog=database;Persist Security Info=False;\"\n  }\n```\n\nIf you need to initialize the database for [IIdGenerator](https://kros-sk.github.io/Kros.Libs.Documentation/api/Kros.Utils/Kros.Data.IIdGenerator.html) then you can call `InitDatabaseForIdGenerator`.\n\n```\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddKorm(Configuration)\n        .InitDatabaseForIdGenerator();\n}\n```\n\n### Unit and performance tests\n\nKros.KORM unit test coverage is more than 87%.\nThere are also some performance test written for Kros.KORM. Here you can see some of their results:\n\n* Reading of 150 000 records with 25 columns (long strings and guids) from DataTable is finished in about 410 ms.\n* Reading of 1 500 records with 25 columns (long strings and guids) from DataTable is finished in about 7 ms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkros-sk%2Fkros.korm.msaccess","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkros-sk%2Fkros.korm.msaccess","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkros-sk%2Fkros.korm.msaccess/lists"}