{"id":20974945,"url":"https://github.com/usausa/smart-net-data-accessor","last_synced_at":"2025-05-14T13:32:17.428Z","repository":{"id":41497631,"uuid":"185200719","full_name":"usausa/Smart-Net-Data-Accessor","owner":"usausa","description":"2-way/outside SQL build-time data accessor generator library.","archived":false,"fork":false,"pushed_at":"2025-04-28T00:05:18.000Z","size":2939,"stargazers_count":25,"open_issues_count":2,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-28T01:20:53.210Z","etag":null,"topics":["2way-sql","codegenerator","dao","data-access","data-access-library","data-mapper","dataaccess","orm","sql"],"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/usausa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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}},"created_at":"2019-05-06T13:19:26.000Z","updated_at":"2025-04-28T00:05:22.000Z","dependencies_parsed_at":"2023-01-23T17:31:07.638Z","dependency_job_id":"7fce44b0-5628-4d4f-b955-a95aa345fad1","html_url":"https://github.com/usausa/Smart-Net-Data-Accessor","commit_stats":{"total_commits":394,"total_committers":1,"mean_commits":394.0,"dds":0.0,"last_synced_commit":"2c12709364cc24187e490d853ff0f6b49b9d8dd8"},"previous_names":[],"tags_count":57,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Data-Accessor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Data-Accessor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Data-Accessor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Data-Accessor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/usausa","download_url":"https://codeload.github.com/usausa/Smart-Net-Data-Accessor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254150600,"owners_count":22022992,"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":["2way-sql","codegenerator","dao","data-access","data-access-library","data-mapper","dataaccess","orm","sql"],"created_at":"2024-11-19T04:35:41.796Z","updated_at":"2025-05-14T13:32:12.394Z","avatar_url":"https://github.com/usausa.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Smart.Data.Accessor .NET - data accessor generator library for .NET\r\n\r\n[![NuGet Badge](https://buildstats.info/nuget/Usa.Smart.Data.Accessor)](https://www.nuget.org/packages/Usa.Smart.Data.Accessor/)\r\n\r\n## What is this?\r\n\r\n* Build-time data accessor generator library.\r\n* 2-way SQL supported.\r\n\r\n## Getting Started(.NET Core Console Application)\r\n\r\nInstall [Usa.Smart.Data.Accessor](https://www.nuget.org/packages/Usa.Smart.Data.Accessor).\r\n\r\nCreate data accessor interface and model class like this.\r\n\r\n```csharp\r\npublic sealed class DataEntity\r\n{\r\n    public long Id { get; set; }\r\n\r\n    public string Name { get; set; }\r\n\r\n    public string Type { get; set; }\r\n}\r\n```\r\n\r\n```csharp\r\nusing System.Collections.Generic;\r\n\r\nusing Smart.Data.Accessor.Attributes;\r\n\r\n[DataAccessor]\r\npublic interface IExampleAccessor\r\n{\r\n    [Execute]\r\n    void Create();\r\n\r\n    [Insert]\r\n    void Insert(DataEntity entity);\r\n\r\n    [Query]\r\n    List\u003cDataEntity\u003e QueryDataList(string type = null);\r\n}\r\n```\r\n\r\nCreate an SQL file with the naming convention of interface name + method name.\r\n\r\nMethods with [Insert] attribute automatically generate SQL, so no file is required.\r\n\r\nBy default, SQL files are placed in the 'Sql' subfolder of the interface file.\r\n\r\n* IExampleAccessor.Create.sql\r\n\r\n```sql\r\nCREATE TABLE IF NOT EXISTS Data (Id int PRIMARY KEY, Name text, Type text)\r\n```\r\n\r\n* IExampleAccessor.QueryDataList.sql\r\n\r\n```sql\r\nSELECT * FROM Data\r\n/*% if (!String.IsNullOrEmpty(type)) { */\r\nWHERE Type = /*@ type */'A'\r\n/*% } */\r\n```\r\n\r\nUse as follows.\r\n\r\n```csharp\r\nusing System;\r\nusing System.IO;\r\n\r\nusing Microsoft.Data.Sqlite;\r\n\r\nusing Smart.Data;\r\nusing Smart.Data.Accessor;\r\nusing Smart.Data.Accessor.Engine;\r\n\r\npublic static class Program\r\n{\r\n    public static void Main()\r\n    {\r\n        // Initialize\r\n        var engine = new ExecuteEngineConfig()\r\n            .ConfigureComponents(c =\u003e\r\n            {\r\n                c.Add\u003cIDbProvider\u003e(new DelegateDbProvider(() =\u003e new SqliteConnection(\"Data Source=test.db\")));\r\n            })\r\n            .ToEngine();\r\n        var factory = new DataAccessorFactory(engine);\r\n\r\n        // Create data accessor\r\n        var dao = factory.Create\u003cIExampleAccessor\u003e();\r\n\r\n        // Create\r\n        dao.Create();\r\n\r\n        // Insert\r\n        dao.Insert(new DataEntity { Id = 1L, Name = \"Data-1\", Type = \"A\" });\r\n        dao.Insert(new DataEntity { Id = 2L, Name = \"Data-2\", Type = \"B\" });\r\n        dao.Insert(new DataEntity { Id = 3L, Name = \"Data-3\", Type = \"A\" });\r\n\r\n        // Query\r\n        var typeA = dao.QueryDataList(\"A\");\r\n        Console.WriteLine(typeA.Count); // 2\r\n\r\n        var all = dao.QueryDataList();\r\n        Console.WriteLine(all.Count); // 3\r\n    }\r\n}\r\n```\r\n\r\n## 2-way SQL\r\n\r\n|   | Type          | Example                                     |\r\n|:-:|---------------|---------------------------------------------|\r\n| @ | parameter     | `/*@ id */`                                 |\r\n| # | raw parameter | `/*# order #/`                              |\r\n| % | code block    | `/*% if (!String.IsNullOrEmpty(name)) { */` |\r\n| ! | pragma        | `/*!using System.Text */`                   |\r\n\r\n### Parameter\r\n\r\n```sql\r\nSELECT * FROM Data WHERE Id = /*@ id */1\r\n```\r\n\r\n### Raw parameter\r\n\r\n```sql\r\nSELECT * FROM Data ORDER BY /*# order */Name\r\n```\r\n\r\n### Code block\r\n\r\n```sql\r\nSELECT * FROM Data\r\n/*% if (IsNotNull(id)) { */\r\nWHERE Id \u003e= /*@ id */0\r\n/*% } */\r\n```\r\n\r\n### Pragma\r\n\r\n* Using\r\n\r\n```sql\r\n/*!using System.Text */\r\n```\r\n\r\n* Using static\r\n\r\n```csharp\r\npublic static class CustomScriptHelper\r\n{\r\n    public static bool HasValue(int? value)\r\n    {\r\n        return value.HasValue;\r\n    }\r\n}\r\n```\r\n\r\n```sql\r\n/*!helper MyLibrary.CustomScriptHelper */\r\nSELECT * FROM Data\r\n/*% if (HasValue(id)) { */\r\nWHERE Id \u003e= /*@ id */0\r\n*% } *\r\n```\r\n\r\n### Built-in helper\r\n\r\n```csharp\r\npublic static class ScriptHelper\r\n{\r\n    public static bool IsNull(object value);\r\n\r\n    public static bool IsNotNull(object value);\r\n\r\n    public static bool IsEmpty(string value);\r\n\r\n    public static bool IsNotEmpty(string value);\r\n\r\n    public static bool Any(Array array);\r\n\r\n    public static bool Any(ICollection ic);\r\n}\r\n```\r\n\r\n## Supported result type\r\n\r\nSupported result type and result mapper factory implmentation.\r\n\r\n| Result mapper factory                                 | Target type            |\r\n|-------------------------------------------------------|------------------------|\r\n| Smart.Data.Accessor.Mappers.SingleResultMapperFactory | string, int, ...       |\r\n| Smart.Data.Accessor.Mappers.TupleResultMapperFactory  | Tuple, ValueTuple, ... |\r\n| Smart.Data.Accessor.Mappers.ObjectResultMapperFactory | Any class              |\r\n\r\n### SingleResultMapperFactory\r\n\r\nMap single column to type.\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ISingleAccessor\r\n{\r\n    // SELECT Name FROM Data\r\n    [Query]\r\n    IList\u003cstring\u003e QueryStringList();\r\n}\r\n```\r\n\r\n### TupleResultMapperFactory\r\n\r\nMap columns to tuple members.\r\nTuple member constructor arguments and properties are supported as destinations.\r\nIf the map destination cannot be found, the target moves to the next member of the tuple.\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ITupleAccessor\r\n{\r\n    // SELECT T0.Date, T0.Amount, T1.Name, T1.Price FROM Transaction T0 INNER JOIN Master T1 ON T0.MasterId = T1.Id\r\n    [Query]\r\n    IList\u003cValueTuple\u003cTransactionEntity, MasterEntity\u003e\u003e QueryTupleList();\r\n}\r\n```\r\n\r\n### ObjectResultMapperFactory\r\n\r\nMap columns to class.\r\nConstructor arguments and properties are supported as destinations.\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ITupleAccessor\r\n{\r\n    // SELECT * FROM ...\r\n    [Query]\r\n    IList\u003cDataEntity\u003e\u003e QueryDataList();\r\n}\r\n```\r\n\r\n## Attributes\r\n\r\n### Data accessor attribute\r\n\r\n* DataAccessorAttribute\r\n\r\n```csharp\r\n// Data accessor interface marker\r\n[DataAccessor]\r\npublic interface IExampleAccessor\r\n{\r\n...\r\n}\r\n```\r\n\r\n### Method attributes\r\n\r\n* ExecuteAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IExecuteAccessor\r\n{\r\n    // Call ExecuteNonQuery()\r\n    [Execute]\r\n    int Update(long id, string name);\r\n\r\n    [Execute]\r\n    ValueTask\u003cint\u003e UpdateAsync(long id, string name);\r\n}\r\n```\r\n\r\n* ExecuteScalarAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IExecuteScalarAccessor\r\n{\r\n    // Call ExecuteScalar()\r\n    [ExecuteScalar]\r\n    long Count();\r\n\r\n    [ExecuteScalar]\r\n    ValueTask\u003clong\u003e CountAsync();\r\n}\r\n```\r\n\r\n* ExecuteReaderAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IExecuteReaderAccessor\r\n{\r\n    // Call ExecuteReader()\r\n    [ExecuteReader]\r\n    IDataReader Enumerate();\r\n\r\n    [ExecuteReader]\r\n    ValueTask\u003cIDataReader\u003e EnumerateAsync();\r\n}\r\n```\r\n\r\n* QueryFirstOrDefaultAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IQueryFirstOrDefaultAccessor\r\n{\r\n    // Call ExecuteReader() and map single object or default\r\n    [QueryFirstOrDefault]\r\n    DataEntity QueryData(long id);\r\n\r\n    [QueryFirstOrDefault]\r\n    ValueTask\u003cDataEntity\u003e QueryDataAsync(long id);\r\n}\r\n```\r\n\r\n* QueryAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IQueryAccessor\r\n{\r\n    // Call ExecuteReader() and map object list bufferd\r\n    [Query]\r\n    IList\u003cDataEntity\u003e QueryBufferd();\r\n\r\n    // Call ExecuteReader() and map object enumerable non-bufferd\r\n    [Query]\r\n    IEnumerable\u003cDataEntity\u003e QueryNonBufferd();\r\n\r\n    [Query]\r\n    ValueTask\u003cIList\u003cDataEntity\u003e\u003e QueryBufferdAsync();\r\n\r\n    [Query]\r\n    IAsyncEnumerable\u003cDataEntity\u003e QueryNonBufferdAsync();\r\n}\r\n```\r\n\r\n### Mapping attributes\r\n\r\n* IgnoreAttribute\r\n\r\n```csharp\r\npublic sealed class DataEntity\r\n{\r\n    // Ignore mapping\r\n    [Ignore]\r\n    public int IgnoreMember { get; set; }\r\n}\r\n```\r\n\r\n* NameAttribute\r\n\r\n```csharp\r\npublic sealed class UserEntity\r\n{\r\n    // Map from USER_NAME column\r\n    [Name(\"USER_NAME\")]\r\n    public string UserName { get; set; }\r\n}\r\n```\r\n\r\n* DirectionAttribute\r\n\r\n```csharp\r\npublic sealed class Parameter\r\n{\r\n    // ParameterDirection.Input is used\r\n    [Input]\r\n    public int InputParameter { get; set; }\r\n\r\n    // ParameterDirection.InputOutput is used\r\n    [InputOutput]\r\n    public int InputOutputParameter { get; set; }\r\n\r\n    // ParameterDirection.Output is used\r\n    [Output]\r\n    public int OutputParameter { get; set; }\r\n\r\n    // ParameterDirection.ReturnValue is used\r\n    [ReturnValue]\r\n    public int ReturnValue { get; set; }\r\n}\r\n```\r\n\r\n### Parameter builder attributes\r\n\r\n* AnsiStringAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IAnsiStringAccessor\r\n{\r\n    // DbType.AnsiStringFixedLength is set\r\n    [QueryFirstOrDefault]\r\n    DataEntity QueryEntity([AnsiString(3)] string id);\r\n}\r\n```\r\n\r\n* DbTypeAttribute\r\n\r\n```csharp\r\npublic sealed class Parameter\r\n{\r\n    // DbType.AnsiStringFixedLength is set\r\n    [DbType(DbType.AnsiStringFixedLength, 3)]\r\n    public string Id { get; set; }\r\n}\r\n```\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IDbTypeAccessor\r\n{\r\n    [QueryFirstOrDefault]\r\n    DataEntity QueryEntity(Parameter parameter);\r\n}\r\n```\r\n\r\n### Result parser attribute\r\n\r\n* ResultParserAttribute\r\n\r\n```csharp\r\npublic sealed class CustomParserAttribute : ResultParserAttribute\r\n{\r\n    public override Func\u003cobject, object\u003e CreateParser(IServiceProvider serviceProvider, Type type)\r\n    {\r\n        return x =\u003e Convert.ChangeType(x, type, CultureInfo.InvariantCulture);\r\n    }\r\n}\r\n```\r\n\r\n```csharp\r\npublic sealed class ParserEntity\r\n{\r\n    // DB value parsed by CustomParserAttribute\r\n    [CustomParser]\r\n    public long Value { get; set; }\r\n}\r\n```\r\n\r\n### Injection attribute\r\n\r\n```csharp\r\npublic sealed class Counter\r\n{\r\n    private long counter;\r\n\r\n    public long Next() =\u003e ++counter;\r\n}\r\n```\r\n\r\n```csharp\r\n[DataAccessor]\r\n[Inject(typeof(Counter), \"counter\")]\r\npublic interface IInjectAccessor\r\n{\r\n...\r\n}\r\n```\r\n\r\n```sql\r\nINSERT INTO Data (Value) VALUES (/*@ counter.Next() */)\r\n```\r\n\r\n### Connection selector attribute\r\n\r\n* ProviderAttribute\r\n\r\n```csharp\r\n// IDbProvider named 'Primary' selected by IDbProviderSelector\r\n[DataAccessor]\r\n[Provider(\"Primary\")]\r\npublic interface IPrimaryAccessor\r\n{\r\n...\r\n}\r\n```\r\n\r\n```csharp\r\n// IDbProvider named 'Secondary' selected by IDbProviderSelector\r\n[DataAccessor]\r\n[Provider(\"Secondary\")]\r\npublic interface ISecondaryAccessor\r\n{\r\n...\r\n}\r\n```\r\n\r\n### Option attribute\r\n\r\n* TimeoutAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ITimeoutAccessor\r\n{\r\n    // timeout is used for IDbCommand.CommandTimeout\r\n    [Execute]\r\n    int Execute([Timeout] int timeout);\r\n}\r\n```\r\n\r\n* CommandTimeoutAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ICommandTimeoutAccessor\r\n{\r\n    // IDbCommand.CommandTimeout = 300000;\r\n    [Execute]\r\n    [CommandTimeout(30000)]\r\n    int Execute();\r\n}\r\n```\r\n\r\n## SQL builder method attributes\r\n\r\nAttributes that automatically generate SQL.\r\n\r\nIt is extensible and can implement its own attributes.\r\n\r\n### Builder attribute\r\n\r\n* InsertAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IInsertAccessor\r\n{\r\n    // DataEntity property is used\r\n    [Insert]\r\n    int Insert(DataEntity entity);\r\n\r\n    // Method arguments is used\r\n    [Insert(typeof(DataEntity))]\r\n    int Insert(long id, string name);\r\n}\r\n```\r\n\r\n* UpdateAttribute\r\n\r\n```csharp\r\npublic sealed class UpdateValues\r\n{\r\n    [Key]\r\n    public long Id { get; set; }\r\n\r\n    public string Name { get; set; }\r\n}\r\n```\r\n\r\n```csharp\r\npublic sealed class UpdateValues\r\n{\r\n    public string Type { get; set; }\r\n\r\n    public string Name { get; set; }\r\n}\r\n```\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IUpdateAccessor\r\n{\r\n    // By entity key memember\r\n    [Update]\r\n    int Update(DataEntity entity);\r\n\r\n    // UPDATE Type and Name by id\r\n    [Update(typeof(DataEntity))]\r\n    int Update([Values] UpdateValues values, long id);\r\n}\r\n```\r\n\r\n* DeleteAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IDeleteAccessor\r\n{\r\n    // Id = /*@ id */\r\n    [Delete]\r\n    int Delete(long id);\r\n\r\n    // By entity key memember\r\n    [Delete]\r\n    int Delete(DataEntity entity);\r\n\r\n    // Force option is required to delete all\r\n    [Delete(typeof(DataEntity), Force = true)]\r\n    int DeleteAll();\r\n\r\n    // Key1 = @key1 AND Key2 \u003e= @key2\r\n    [Delete]\r\n    int Delete(long key1, [Condition(Operand.GreaterEqualThan)] long key2);\r\n}\r\n```\r\n\r\n* SelectAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ISelectAccessor\r\n{\r\n    // Conditoon\r\n\r\n    // Key1 = @key1 AND Key2 \u003e= @key2\r\n    [Select]\r\n    List\u003cDataEntity\u003e SelectListByCondition(long key1, [Condition(Operand.GreaterEqualThan)] long key2);\r\n\r\n    // Order\r\n\r\n    // Key order is default\r\n    [Select]\r\n    List\u003cDataEntity\u003e SelectListKeyOrder();\r\n\r\n    // Attribute property based order\r\n    [Select(Order = \"Name DESC\")]\r\n    List\u003cDataEntity\u003e SelectListCustomOrder();\r\n\r\n    // ORDER BY /*# order */\r\n    [Select]\r\n    List\u003cDataEntity\u003e SelectParameterOrder([Order] string order);\r\n\r\n    //  map to other entity\r\n\r\n    // SQL is generated based on DataEntity and map to OtherEntity\r\n    [Select(typeof(DataEntity))]\r\n    List\u003cOtherEntity\u003e SelectListByType();\r\n\r\n    // SQL is generated with table name 'Data' and map to OtherEntity\r\n    [Select(\"Data\")]\r\n    List\u003cOtherEntity\u003e SelectListByName();\r\n}\r\n```\r\n\r\n* SelectSingleAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ISelectAccessor\r\n{\r\n    // Id = /*@ id */\r\n    [SelectSingle]\r\n    DataEntity SelectSingle(long id);\r\n\r\n    // By entity key memember\r\n    [SelectSingle]\r\n    DataEntity SelectSingle(DataEntity entity);\r\n}\r\n```\r\n\r\n* CountAttribute\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ICountAccessor\r\n{\r\n    // Count all\r\n    [Count(typeof(DataEntity))]\r\n    long CountAll();\r\n\r\n    // Count where Value \u003e= /*@ value */\r\n    [Count(typeof(DataEntity))]\r\n    long CountAll([Condition(Operand.GreaterEqualThan)] long value);\r\n}\r\n```\r\n\r\n* ProcedureAttribute\r\n\r\n```sql\r\nCREATE PROCEDURE PROC1\r\n    @param1 INT,\r\n    @param2 INT OUTPUT,\r\n    @param3 INT OUTPUT\r\nAS\r\nBEGIN\r\n    SELECT @param2 = @param2 + 1\r\n    SELECT @param3 = @param1 + 1\r\n    RETURN 100\r\nEND\r\n```\r\n\r\n```csharp\r\npublic sealed class Parameter\r\n{\r\n    [Input]\r\n    [Name(\"param1\")]\r\n    public int Parameter1 { get; set; }\r\n\r\n    [InputOutput]\r\n    [Name(\"param2\")]\r\n    public int Parameter2 { get; set; }\r\n\r\n    [Output]\r\n    [Name(\"param3\")]\r\n    public int Parameter3 { get; set; }\r\n\r\n    [ReturnValue]\r\n    public int ReturnValue { get; set; }\r\n}\r\n```\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IProcedureAccessor\r\n{\r\n    // Argument version\r\n    [Procedure(\"PROC1\")]\r\n    int Execute(int param1, ref int param2, out int param3);\r\n\r\n    // Parameter class version\r\n    [Procedure(\"PROC1\")]\r\n    void Execute(Parameter parameter);\r\n}\r\n```\r\n\r\n```csharp\r\nvar param2 = 2;\r\nvar ret = dao.Execute(1, ref param2, out var param3);\r\n// param2 = 3, param3 = 2, ret = 100\r\n```\r\n\r\n```csharp\r\nvar parameter = new Parameter { Parameter1 = 1, Parameter2 = 2 };\r\ndao.Execute(parameter);\r\n// Parameter2 = 3, Parameter3 = 2, ReturnValue = 100\r\n```\r\n\r\n### Condition attribute\r\n\r\n```csharp\r\n// Generate condition\r\n\r\n// Kye \u003e= /*@ key */\r\n[Delete]\r\nint Delete([Condition(Operand.GreaterEqualThan)] long key);\r\n\r\n// /*% if (IsNotNull(type)) { %//*@ type *//*% } */\r\n[Select]\r\nList\u003cDataEntity\u003e Select([Condition(ExcludeNull = true)] string type);\r\n\r\n// /*% if (IsNotEmpty(type)) { %//*@ type *//*% } */\r\n[Select]\r\nList\u003cDataEntity\u003e Select([Condition(ExcludeEmpty = true)] string typel);\r\n```\r\n\r\n### Value attribute\r\n\r\n* DbValueAttribute\r\n\r\n```csharp\r\npublic sealed class DbValueEntity\r\n{\r\n    [Key]\r\n    public long Id { get; set; }\r\n\r\n    // DB value CURRENT_TIMESTAMP is used\r\n    [DbValue(\"CURRENT_TIMESTAMP\")]\r\n    public string DateTime { get; set; }\r\n}\r\n```\r\n\r\n* CodeValueAttribute\r\n\r\n```csharp\r\npublic sealed class DataEntity\r\n{\r\n    [Key]\r\n    public string Key { get; set; }\r\n\r\n    // Code counter.Next() is used\r\n    [CodeValue(\"counter.Next()\")]\r\n    public long Value { get; set; }\r\n}\r\n```\r\n\r\n```csharp\r\n[DataAccessor]\r\n[Inject(typeof(Counter), \"counter\")]\r\npublic interface ICodeValueAccessor\r\n{\r\n    [Insert]\r\n    void Insert(DataEntity entity);\r\n}\r\n```\r\n\r\n### Option builders\r\n\r\nSupport database specific UPSERT, SELECT FOR UPDATE, etc.\r\n\r\n| Package | Database   |\r\n|-|-|\r\n| [![NuGet Badge](https://buildstats.info/nuget/Usa.Smart.Data.Accessor.Options.SqlServer)](https://www.nuget.org/packages/Usa.Smart.Data.Accessor.Options.SqlServer/) | SQL Server |\r\n| [![NuGet Badge](https://buildstats.info/nuget/Usa.Smart.Data.Accessor.Options.MySql)](https://www.nuget.org/packages/Usa.Smart.Data.Accessor.Options.MySql/) | MySQL |\r\n| [![NuGet Badge](https://buildstats.info/nuget/Usa.Smart.Data.Accessor.Options.Postgres)](https://www.nuget.org/packages/Usa.Smart.Data.Accessor.Options.Postgres/) | PostgreSQL |\r\n\r\n## Special arguments\r\n\r\n### DbConnection\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IDbConnectionAccessor\r\n{\r\n    // DbConnection con is used insted of default IDbProvider connection\r\n    [Execute]\r\n    int Execute(DbConnection con);\r\n}\r\n```\r\n\r\n### DbTransaction\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface ITransactionAccessor\r\n{\r\n    // DbTransaction tx is used as transaction and connection\r\n    [Execute]\r\n    int Execute(DbTransaction tx, long id, string name);\r\n}\r\n```\r\n\r\n```csharp\r\nusing (var tx = con.BeginTransaction())\r\n{\r\n    var effect = accessor.Execute(tx, 1L, \"xxx\");\r\n\r\n    tx.Commit();\r\n}\r\n```\r\n\r\n### CancellationToken\r\n\r\n```csharp\r\n[DataAccessor]\r\npublic interface IExecuteCancelAsyncAccessor\r\n{\r\n    // Cancelable async method\r\n    [Execute]\r\n    ValueTask\u003cint\u003e ExecuteAsync(CancellationToken cancel);\r\n}\r\n```\r\n\r\n## Configuration\r\n\r\nExecuteEngineConfig configuration.\r\n\r\n### IDbProvider\r\n\r\n```csharp\r\n// Default IDbProvider configuration\r\nvar engine = new ExecuteEngineConfig()\r\n    .ConfigureComponents(c =\u003e c.Add\u003cIDbProvider\u003e(new DelegateDbProvider(() =\u003e new SqlConnection(ConnectionString))))\r\n    .ToEngine();\r\n```\r\n\r\n```csharp\r\n// Use multiple provider\r\nconfig.ConfigureComponents(c =\u003e\r\n{\r\n    var selector = new NamedDbProviderSelector();\r\n    selector.AddProvider(\"Main\", new DelegateDbProvider(() =\u003e new SqlConnection(MainConnectionString)));\r\n    selector.AddProvider(\"Sub\", new DelegateDbProvider(() =\u003e new SqlConnection(SubConnectionString)));\r\n    c.Add\u003cIDbProviderSelector\u003e(selector);\r\n});\r\n```\r\n\r\n### Type map\r\n\r\n```csharp\r\n// Use DbType.AnsiString for string\r\nconfig.ConfigureTypeMap(map =\u003e map[typeof(string)] = DbType.AnsiString);\r\n```\r\n\r\n### Type handler\r\n\r\n```csharp\r\npublic sealed class DateTimeTickTypeHandler : ITypeHandler\r\n{\r\n    public void SetValue(DbParameter parameter, object value)\r\n    {\r\n        parameter.DbType = DbType.Int64;\r\n        parameter.Value = ((DateTime)value).Ticks;\r\n    }\r\n\r\n    public Func\u003cobject, object\u003e CreateParse(Type type)\r\n    {\r\n        return x =\u003e new DateTime((long)x);\r\n    }\r\n}\r\n```\r\n\r\n```csharp\r\n// In database, store DateTime using bigint\r\nconfig.ConfigureTypeHandlers(handlers =\u003e handlers[typeof(DateTime)] = new DateTimeTickTypeHandler());\r\n```\r\n\r\n### Result mapper factory\r\n\r\n```csharp\r\n// Implement custom result mapper factory\r\npublic interface IResultMapperFactory\r\n{\r\n    bool IsMatch(Type type);\r\n\r\n    ResultMapper\u003cT\u003e CreateMapper\u003cT\u003e(IResultMapperCreateContext context, Type type, ColumnInfo[] columns);\r\n}\r\n```\r\n\r\n```csharp\r\n// Use custom result mapper factory\r\nconfig.ConfigureResultMapperFactories(mappers =\u003e mappers.Add(new CustomResultMapperFactory));\r\n```\r\n\r\n## ASP.NET Core integration\r\n\r\n```csharp\r\nservices.AddSingleton\u003cIDbProvider\u003e(new DelegateDbProvider(() =\u003e new SqliteConnection(\"Data Source=test.db\")));\r\n\r\nservices.AddDataAccessor(config =\u003e\r\n{\r\n    config.AccessorAssemblies.Add(Assembly.GetExecutingAssembly());\r\n});\r\n```\r\n\r\n```csharp\r\nprivate readonly ISampleAccessor sampleAccessor;\r\n\r\npublic HomeController(ISampleAccessor sampleAccessor)\r\n{\r\n    this.sampleAccessor = sampleAccessor;\r\n}\r\n```\r\n\r\n## Code generation\r\n\r\n### Config attributes\r\n\r\n* EntitySuffixAttribute\r\n\r\nClass suffix to convert table name.\r\nDefault suffis is `Entity` and `Model`.\r\n\r\n* NamingAttribute\r\n\r\nNaming rule to convert column name.\r\n\r\n| Attribute                                             |\r\n|-------------------------------------------------------|\r\n| Smart.Data.Accessor.Configs.DefaultNamingAttribute    |\r\n| Smart.Data.Accessor.Configs.SnakeNamingAttribute      |\r\n| Smart.Data.Accessor.Configs.UpperSnakeNamingAttribute |\r\n| Smart.Data.Accessor.Configs.CamelNamingAttribute      |\r\n\r\n### Generated source\r\n\r\nGenerated source is created at `$(ProjectDir)$(IntermediateOutputPath)SmartDataAccessor`.\r\n\r\n## Benchmark (for reference purpose only)\r\n\r\n``` ini\r\n\r\nBenchmarkDotNet=v0.13.1, OS=Windows 10.0.22621\r\nAMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores\r\n.NET SDK=7.0.100\r\n  [Host]    : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT\r\n  MediumRun : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT\r\n\r\nJob=MediumRun  IterationCount=15  LaunchCount=2  \r\nWarmupCount=10  \r\n\r\n```\r\n|                            Method |        Mean |     Error |    StdDev |         Min |         Max |         P90 |  Gen 0 |  Gen 1 | Allocated |\r\n|---------------------------------- |------------:|----------:|----------:|------------:|------------:|------------:|-------:|-------:|----------:|\r\n|                     DapperExecute |   182.55 ns |  2.567 ns |  3.843 ns |   177.16 ns |   189.54 ns |   187.94 ns | 0.0272 |      - |     456 B |\r\n|                      SmartExecute |    79.19 ns |  0.407 ns |  0.610 ns |    78.00 ns |    80.43 ns |    79.78 ns | 0.0219 |      - |     368 B |\r\n|               DapperExecuteScalar |    59.11 ns |  0.253 ns |  0.363 ns |    58.59 ns |    60.02 ns |    59.59 ns | 0.0086 |      - |     144 B |\r\n|                SmartExecuteScalar |    43.55 ns |  0.198 ns |  0.291 ns |    42.78 ns |    44.11 ns |    43.92 ns | 0.0086 |      - |     144 B |\r\n|             DapperQueryBufferd100 | 2,467.93 ns | 12.487 ns | 18.690 ns | 2,429.29 ns | 2,505.93 ns | 2,495.21 ns | 0.3471 | 0.0038 |   5,832 B |\r\n|              SmartQueryBufferd100 | 1,656.82 ns |  6.230 ns |  8.733 ns | 1,642.46 ns | 1,680.08 ns | 1,666.48 ns | 0.3300 | 0.0057 |   5,536 B |\r\n|     SmartQueryBufferd100Optimized | 1,646.78 ns |  7.451 ns | 10.445 ns | 1,620.13 ns | 1,672.51 ns | 1,657.38 ns | 0.3300 | 0.0057 |   5,536 B |\r\n|         DapperQueryFirstOrDefault |   219.29 ns |  1.832 ns |  2.686 ns |   214.77 ns |   223.51 ns |   222.33 ns | 0.0253 |      - |     424 B |\r\n|          SmartQueryFirstOrDefault |   115.53 ns |  1.979 ns |  2.774 ns |   112.03 ns |   120.31 ns |   118.94 ns | 0.0186 |      - |     312 B |\r\n| SmartQueryFirstOrDefaultOptimized |    83.91 ns |  0.813 ns |  1.217 ns |    82.00 ns |    86.71 ns |    85.52 ns | 0.0186 |      - |     312 B |\r\n|               DapperWithCondition |   224.01 ns |  0.761 ns |  1.115 ns |   221.79 ns |   225.92 ns |   225.49 ns | 0.0491 |      - |     824 B |\r\n|                SmartWithCondition |    83.14 ns |  0.977 ns |  1.462 ns |    80.77 ns |    85.65 ns |    85.12 ns | 0.0219 |      - |     368 B |\r\n\r\n## Example Project\r\n\r\n* [Console example](https://github.com/usausa/Smart-Net-Data-Accessor/tree/master/Example.ConsoleApplication)\r\n* [Web example](https://github.com/usausa/Smart-Net-Data-Accessor/tree/master/Example.WebApplication)\r\n* [Web example with Smart.Resolver](https://github.com/usausa/Smart-Net-Data-Accessor/tree/master/Example.WebApplication2)\r\n\r\n## TODO\r\n\r\n* Code generator version (1.3+).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusausa%2Fsmart-net-data-accessor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fusausa%2Fsmart-net-data-accessor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusausa%2Fsmart-net-data-accessor/lists"}