{"id":19303196,"url":"https://github.com/argentini/argentini.datastore","last_synced_at":"2025-04-22T11:32:01.107Z","repository":{"id":50607802,"uuid":"497401449","full_name":"argentini/Argentini.DataStore","owner":"argentini","description":"SQL Server ORM library that stores models as JSON data with custom indexed computed columns for fast search and ordering (like mongodb). DataStore uses a fluent pattern for powerful querying and ordering of paged data, and parallel bulk saves (Windows, macOS, Linux, .NET 8.0, x64, Arm64, Apple Silicon)","archived":false,"fork":false,"pushed_at":"2024-05-15T20:49:23.000Z","size":270,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-01T22:46:52.223Z","etag":null,"topics":["dal","database","dotnet","dotnet6","mongodb","orm","sql-server"],"latest_commit_sha":null,"homepage":"https://nonsequiturs.com/","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/argentini.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2022-05-28T18:40:07.000Z","updated_at":"2024-05-15T20:49:26.000Z","dependencies_parsed_at":"2023-11-14T21:44:41.844Z","dependency_job_id":null,"html_url":"https://github.com/argentini/Argentini.DataStore","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/argentini%2FArgentini.DataStore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/argentini%2FArgentini.DataStore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/argentini%2FArgentini.DataStore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/argentini%2FArgentini.DataStore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/argentini","download_url":"https://codeload.github.com/argentini/Argentini.DataStore/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250232160,"owners_count":21396582,"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":["dal","database","dotnet","dotnet6","mongodb","orm","sql-server"],"created_at":"2024-11-09T23:25:25.351Z","updated_at":"2025-04-22T11:32:00.168Z","avatar_url":"https://github.com/argentini.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DataStore\n\nDataStore is a high performance JSON object store (ORM) for SQL Server. DataStore uses and automatically creates and manages a pre-defined SQL Server data structure that can coexist with existing database objects. All database operations are performed with the DataStore class.  \n\nYour models are stored as JSON so you can have most any kind of object structure, provided your models inherit from DsObject.\n\n## Basic Example\n\nInstantiating DataStore with settings is non-destructive. Any existing DataStore tables are left untouched. Methods to delete all or unused schema objects are provided for those edge cases.  \n\n### Models\n\nInstantiate DataStore with a settings object and database schema will be created for all classes that inherit from DsObject. The following attributes can be used in your classes:  \n\n- *DsNoDatabaseTable* prevents DataStore from creating a table for the class.\n- *DsUseLineageFeatures* enables lineage features for that table; add to the class itself.\n- *DsSerializerContext(typeof(...))* to provide a de/serialization speed boost by using source generator *JsonSerializationContext* classes for each table; add to the class itself.\n- *DsIndexedColumn* generates a SQL computed column with index for faster queries on that data; add to properties and fields.\n- *DsIndexedColumn(\"Food\",\"Email\")* generates indexed SQL computed columns for faster queries on the dictionary key names specified; add to Dictionary properties and fields.\n\n```C#\n[DsUseLineageFeatures]\n[DsSerializerContext(typeof(UserJsonSerializerContext))]\npublic class User: DsObject\n{\n    [DsIndexedColumn]\n    public string Firstname { get; set; }\n    \n    [DsIndexedColumn]\n    public int Age { get; set; }\n    \n    public List\u003cPermissions\u003e Permissions { get; set; }\n    \n    [DsIndexedColumn(\"Food\", \"Color\")]\n    public Dictionary\u003cstring, string\u003e Favorites { get; set; } = new();\n}\n\n[JsonSerializable(typeof(User))]\n[JsonSourceGenerationOptions(WriteIndented = false)]\ninternal partial class UserJsonSerializerContext : JsonSerializerContext\n{ }\n```\n\n### Construction\n\nYou can create a DataStore instance anywhere in your code:\n\n```C#\nvar dataStore = new DataStore(new DataStoreSettings {\n    SqlConnectionString = sqlConnectionString,\n    UseIndexedColumns = true\n});\n```\n\nYou can also use DataStore as a singleton service:\n\n```C#\nservices.AddSingleton\u003cDataStore\u003e((factory) =\u003e new DataStore(new DataStoreSettings {\n    SqlConnectionString = sqlConnectionString,\n    UseIndexedColumns = true\n}));\n```\n\n### Create and Save Objects\n\nCreating and saving a DataStore object is simple:\n\n```C#\nvar user = new User\n{\n    FirstName = \"Michael\",\n    LastName = \"Argentini\",\n    Age = 50,\n    Permissions = new List\u003cPermission\u003e\n    {\n        new() { Role = \"user\" },\n        new() { Role = \"admin\" },\n        // etc.\n    }\n};\n\nawait dataStore.SaveAsync(user);\n```\n\nThe saved object is updated with any changes, like lineage and depth information, creation or last update date, etc. And you can provide a list of objects to save them all in one call.  \n\n### Read Objects\n\nQuerying the database for objects is simple too. In any read calls you can specify a DsQuery object with a fluent-style pattern for building your query. In the query you can specify property names as strings with dot notation:\n\n```C#\nvar users = await dataStore.GetManyAsync\u003cUser\u003e(\n    page: 1,\n    perPage: 50,\n    new DsQuery()\n        .StringProp(\"LastName\").EqualTo(\"Argentini\")\n        .AND()\n        .StringProp(\"Permissions.Role\").EqualTo(\"admin\")\n        .AND()\n        .GroupBegin()\n            .NumberProp\u003cint\u003e(\"Age\").EqualTo(50)\n            .OR()\n            .NumberProp\u003cint\u003e(\"Age\").EqualTo(51)\n        .GroupEnd(),\n    new DsOrderBy()\n        .Prop\u003cint\u003e(\"Age\").Ascending()\n);\n```\n\nOr you can use the model structure to specify names, and make code refactoring easier:\n\n```C#\nvar users = await dataStore.GetManyAsync\u003cUser\u003e(\n    page: 1,\n    perPage: 50,\n    new DsQuery()\n        .StringProp\u003cUser\u003e(u =\u003e u.LastName).EqualTo(\"Argentini\")\n        .AND()\n        .StringProp\u003cUser, Role\u003e(u =\u003e u.Permissions, r =\u003e r.Role).EqualTo(\"admin\")\n        .AND()\n        .GroupBegin()\n            .NumberProp\u003cUser,int\u003e(u =\u003e u.Age).EqualTo(50)\n            .OR()\n            .NumberProp\u003cUser,int\u003e(u =\u003e u.Age).EqualTo(51)\n        .GroupEnd(),\n    new DsOrderBy()\n        .Prop\u003cUser\u003e(o =\u003e o.Age).Ascending()\n);\n```\n\n### Dynamic Property Access\n\nIf you need to access object properties without knowing the object type, DsObject exposes JSON features that allow you to access property values using standard JSON path syntax:\n\n```C#\nvar users = await dataStore.GetManyAsync\u003cUser\u003e(\n    page: 1,\n    perPage: 50\n);\n\nforeach (DsObject dso in users)\n{\n    dso.Serialize(dataStore);\n\n    var lastName = dso.Value\u003cstring\u003e(\"$.LastName\");\n    var roles = dso.Values(typeof(string), \"$.Permissions.Role\");\n\n    // etc.\n}\n\n```\n\n**Remember:** these JSON features are read-only. If you change a property value in the DsObject you will need to call *Serialize()* again to update the JSON representation.\n\n\n### Project\n\nThis project is a .NET library with xUnit tests, so you can easily play with DataStore. These tests show how to use DataStore as well as benchmark its performance.  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fargentini%2Fargentini.datastore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fargentini%2Fargentini.datastore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fargentini%2Fargentini.datastore/lists"}