{"id":17058826,"url":"https://github.com/jpvenson/dataaccess","last_synced_at":"2025-04-12T17:51:04.942Z","repository":{"id":20644661,"uuid":"23926608","full_name":"JPVenson/DataAccess","owner":"JPVenson","description":"This is Yet another ORM that uses various Technology's without 3rd Party to Map database output to POCOs. ","archived":false,"fork":false,"pushed_at":"2023-04-12T23:10:59.000Z","size":24018,"stargazers_count":7,"open_issues_count":1,"forks_count":6,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-04T15:41:46.741Z","etag":null,"topics":["ado","c-sharp","database","orm-framework","poco","reflection"],"latest_commit_sha":null,"homepage":"http://www.jean-pierre-bachmann.dev","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JPVenson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["JPVenson"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2014-09-11T16:38:59.000Z","updated_at":"2025-02-27T07:37:59.000Z","dependencies_parsed_at":"2024-10-14T10:41:22.369Z","dependency_job_id":null,"html_url":"https://github.com/JPVenson/DataAccess","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JPVenson%2FDataAccess","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JPVenson%2FDataAccess/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JPVenson%2FDataAccess/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JPVenson%2FDataAccess/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JPVenson","download_url":"https://codeload.github.com/JPVenson/DataAccess/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248610407,"owners_count":21132920,"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":["ado","c-sharp","database","orm-framework","poco","reflection"],"created_at":"2024-10-14T10:31:09.402Z","updated_at":"2025-04-12T17:51:04.932Z","avatar_url":"https://github.com/JPVenson.png","language":"C#","readme":"[![Build status](https://ci.appveyor.com/api/projects/status/vatab1g9oyo6sriq/branch/master?svg=true)](https://ci.appveyor.com/project/JPVenson/dataaccess/branch/master)\n\n## YAORM now supports folloring Frameworks: netstandard2.0;netcoreapp2.2;netcoreapp2.1;netcoreapp2.0;net47;net471;net472\n\n### if you got trouble with the SqLite Adapter please see the wiki \"SqLite\"\n\nThis work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.\n\nIf you have questions please feel free to just open a Issue https://github.com/JPVenson/DataAccess/issues/new.\n\n## Introduction\nThis will be a short article about my multi strategy ADO.NET wrapper that uses FactoryMethods,\nReflection or a combination of both. It is simple to use,\nbut a complex and powerful solution for simple and fast (fast in Development and usage) database access.\n\nTo be clear, this is designed to be a helper for very simple work. It is not created to be an EF alternative!\n\n## Background\nWell, the background of this project was that most of my colleagues worked with a very old and oversized solution that needed a lot of maintenance and changes when we started with a new project and even for simple statements like:\n\n```SQL\nSELECT * FROM Foo\n```\nI was forced to manually open a connection, run the statement and parse the IDataReader. I thought this is absolutely not necessary because: Most of the time, the POCOs are designed like the database with properties that are named like Column names and so on. So, this was a task I’d tried to automate.\n\nI'd like to present my solution and I hope to get some nice ideas from you.\n\n# Using the Code\nThe main parts are the IDatabase, IDatabaseStrategy and for the Main Reflection and loading the DbAccessLayer.\n\nIDatabase defines a ínterface that maintains a Connection, this means to open a Connection, keep it open as long as it is necessary and then close it. In IDatabase, there is an IDatabaseStrategy that is used to connect to certain databases like MySQL, MsSql, OleDB and so on. The lib supports MsSQL, Obdc, OleDb from the hood, but in others, in the project included Assemblies, there are also implementations for MySQL and SqLite.\n\nAs I mentioned, there are multiple ways to load or submit data from and to a database.\n\nFor example: the simple Select from a database. We expect to be a database that is called Northwind and a Table Foo.\n\nCreate an Object that is called like your Table (Foo)\nDefine properties that are named and of the same type like a Column\nCreate a new Object of DbAccessLayer with a proper connection string Call\n```C#\nSelect\u003cFoo\u003e();\n```\nIn these 4 steps, you will execute a complete select to the database and then the result will be mapped with Reflection to the Object.\n\n```C#\npublic class FooTest\n{\n\tpublic class Foo\n\t{\n\t\tpublic long Id_Foo { get; set; }\n\t\tpublic string FooName { get; set; }\n\t}\n\n\tpublic FooTest()\n\t{\n\tvar accessLayer = new DbAccessLayer(DbTypes.MsSql, \"Data Source=(localdb)\\\\Projects;Initial Catalog=Northwind;Integrated Security=True;\");\n\tvar @select = accessLayer.Select\u003cFoo\u003e();\n\t}\n}\n```\nThere are A LOT of overloads of Select, SelectNative, SelectWhere and RunPrimetivSelect. Almost all methods with a Generic Parameter have a corresponding method that accepts a Type instance.\n\nIn all examples, when an instance of DbAccessLayer is needed, it will be represented by the variable.\n\naccessLayer\nand in the testing, an MsSQL Db is used and its syntax.\n\n# Creating and Customizing a POCO\nThis is primarily an Object Relationship Mapper. That means that this lib always tries to map the output that is returned by a Query into an Object that has multiple properties. You have some attributes that define certain parts and functions of that object.\n\nAs seen in the example, you can skip all extra configuration when you follow some rules. To \"bypass\" these rules like the Rule that a Class must be named the same, then the Table you can set an Attribute.\n\n## ForModel\n\n```C#\n[ForModel(\"Foo\")]\npublic class NotFooButSomeStrangeNameYouDoNotLike\n{\n\tpublic long Id_Foo { get; set; }\n\t[ForModel(\"FooName\")]\n\tpublic string Metallica4tw { get; set; }\n}\n```\nThe ForModel attribute is allowed on Class | Table and on Property | Column level. It gives the Processor the information that the name that is used in the POCO must be mapped to the Table.\n\n## PrimaryKey\n\n```C#\npublic class Foo\n{\n\t[PrimaryKey]\n\tpublic long Id_Foo { get; set; }\n\tpublic string FooName { get; set; }\n}\n```\nThe PrimaryKey attribute marks a Property ... what a wonder, to be an PrimaryKey on the database. With this function, you can call:\n```C#\naccessLayer.Select\u003cFoo\u003e\n(155151 /*This is the PrimaryKey we are looking for*/);\n```\n## InsertIgnore\n\nMarks a Property to be not Automatically included into a InsertStatement. Per default, the PrimaryKey inherits from this attribute.\n\n## ForeignKey\n\nWith Foreign keys you can load NavigationProperties from another entity where a relation exists. To Mark an property as an NavigationProperty you have to annoatate them with the `[ForeignKey(foreignKey, referenceKey)]` Attribute where the `foreignKey` is the name of the column on your current entity and the `referenceKey` is the name of the column that should be mapped to. The type of the Property will be used to Join the tables.\n\n```C#\npublic class FooTest\n{\n\tpublic class Foo\n\t{\n\t\t[PrimaryKey]\n\t\tpublic long Id_Foo { get; set; }\n\t\tpublic string FooName { get; set; }\n\n\t\tpublic long Image_Id { get; set; }\n\n\t\t/// \u003csummary\u003e\n\t\t/// \tA Property that is of the type that is referred to\n\t\t/// \t1 TO 1 relation\n\t\t\u003c/summary\u003e\n\t\t[ForeignKey(\"Image_Id\", \"Image_Id\")]\n\t\tpublic virtual Image img { get; set; }\n\n\t\t/// \u003csummary\u003e\n\t\t/// \tA Property that is a List of the type that is referred to\n\t\t/// \t1 TO Many relation\n\t\t\u003c/summary\u003e\n\t\t[ForeignKey(\"Image_Id\", \"Image_Id\")]\n\t\tpublic virtual DbCollection\u003cImage\u003e imgs { get; set; }\n\t}\n\n\tpublic class Image\n\t{\n\t\t[PrimaryKey]\n\t\tpublic long Id_Image { get; set; }\n\t\tpublic byte[] ImageData { get; set; }\n\t}\n}\n```\n\nThere are some restraints you have to take care of. The Navigation Property must be virtual and if its a 1-n relation it must be ether directly an `DbCollection` or assignable from it, that means it could be an ICollection\u003cT\u003e. \n\n\n\n## LoadNotImplimentedDynamic\n\nWhen the Select statement returns more information than build in the POCO, this property\n(must have this signature):\n\n```C#\n[LoadNotImplimentedDynamic]\npublic IDictionary\u003cstring, object\u003e UnresolvedObjects { set; get; }\n```\n(Property Name does not matter) it will be filled with the data (see FactoryMethods).\n\n## IgnoreReflection\n\nSimple: as the XmlIgnore attribute, it marks a Property to not be indexed and accessed by any function of the Mapper. Even if the result contains a Column that matches this property, the property will not be used.\n\n## RowVersion\n\nDefines a RowVersion attribute. When defined, all calls of `accessLayer.Update()` and `accessLayer.Refresh()` will use this Property to check for changes.\n\n### Loading Strategies\nThere are 2 ways of loading with factory methods defined inside the POCO or automatically with customization over attributes. The 2nd way will be the fallback when there are no or not the right Factory available.\n\n## Constructor and Method Injection\n\nThe manager can detect a method to pull statements from it. For example, how you define a method that creates a Select statement without parameter:\n\n```C#\npublic class Foo\n{\n\tpublic long Id_Foo { get; set; }\n\tpublic string FooName { get; set; }\n\n\t[SelectFactoryMehtod]\n\tpublic static string CreateSelectStatement()\n\t{\n\t\treturn \"SELECT * FROM Foo\";\n\t}\n}\n```\nWhen some method is defined, the manager will always use this method to create a Select statement and he will skip any other reflection based creation.\n\nFor Selects, this is also possible on Class level:\n\n```C#\n[SelectFactory(\"SELECT * FROM Foo\")]\npublic class Foo\n```\n\nBut only Selects must be Public and Static. Update, Insert and Delete Factory’s must be Not static. You can return a string OR an instance of IQueryFactoryResult. To prevent SqlInjection, this is the HEAVILY recommended way when you work with parameters.\n\nAn example that uses IQueryFactoryResult for Update and Delete and a String for Select:\n\n```C#\n[SelectFactory(\"SELECT * FROM Foo\")]\npublic class Foo\n{\n\tpublic long Id_Foo { get; set; }\n\tpublic string FooName { get; set; }\n\n\t[DeleteFactoryMethod]\n\tpublic IQueryFactoryResult CreateDeleteStatement()\n\t{\n\t\tvar result = new QueryFactoryResult(\"DELETE FROM Foo WHERE Id_Foo = @1\",\n\t\tnew QueryParameter()\n\t\t{\n\t\tName = \"@1\", Value = Id_Foo\n\t});\n\treturn result;\n}\n\n[UpdateFactoryMethod]\npublic IQueryFactoryResult CreateSomeKindOfUpdate()\n{\n\tvar result = new QueryFactoryResult(\"Update Foo SET FooName = @param WHERE Id_Foo = @1\",\n\tnew QueryParameter()\n\t{\n\t\tName = \"@1\",\n\t\tValue = Id_Foo\n\t},\n\tnew QueryParameter()\n\t{\n\t\tName = \"@param\",\n\t\tValue = FooName\n\t});\n\treturn result;    \n}\n```\nIt is possible to transfer parameters from the caller to the function. When the caller provides you parameters, they will be given to the function that has the same signature then the parameter. This idea is more or less shamelessly stolen from the ASP.NET MVC approach.\n\nAfter version 2.0.0.14 you can also use an QueryBuilder or QueryBuilderX on a void Method to create your Statements.\n\n```C#\npublic class FooTest\n{\n\tpublic class Foo\n\t{\n\t\tpublic long Id_Foo { get; set; }\n\t\tpublic string FooName { get; set; }\n\n\t\t[UpdateFactoryMethod]\n\t\tpublic static IQueryFactoryResult CreateSomeKindOfUpdate(string someExternalInfos)\n\t\t{\n\t\t\tif (string.IsNullOrEmpty(someExternalInfos))\n\t\t\treturn null; //Noting to do here, use the Automatic loading\n\n\t\t\tvar result = new QueryFactoryResult\n\t\t\t(\"SELECT * FROM Foo f WHERE f.FooName = @info\", \n\t\t\tnew QueryParameter()\n\t\t\t{\n\t\t\t\tValue = someExternalInfos,\n\t\t\t\tName = \"@info\"\n\t\t\t});\n\t\t\treturn result;\n\t}\n\n\n\tpublic FooTest()\n\t{\n\t\tvar access = new DbAccessLayer(DbTypes.MsSql, \"Data Source=(localdb)\\\\Projects;Initial Catalog=Northwind;Integrated Security=True;\");\n\t\tvar @select = access.Select\u003cFoo\u003e(\"SomeName\");\n\t}\n}\n```\nThe string that we provided to...\n\n```C#\naccess.Select\u003cFoo\u003e(\"SomeName\");\n```\n...will be given to the Select function to create a statement and this statement will be executed.\n\nIt is also possible to control the Loading from a DataRecord to your class by using a Constructor that accepts these parameters:\n\n```C#\npublic class Foo\n{\n\t[ObjectFactoryMethod]\n\tpublic Foo(IDataRecord record)\n\t{\n\t\tId_Foo = (long)record[\"Id_Foo\"];\n\t\tFooName = (string)record[\"FooName\"];\n\t}\n\n\tpublic long Id_Foo { get; set; }\n\tpublic string FooName { get; set; }\n}\n```\nWhen it is necessary to create a new Instance of that Poco, there is always a IDataRecord to load it from so via Constructor injection, we find this one and provide him the data.\n\n## XML Field Loading\nThere is a new attribute:\n\n## FromXmlAttribute\nIt allows a simple loading of Objects from an XML Serialized Column. The attribute contains two parameters:\n\nFieldName [Required]\nLoadStrategy [Optional]\nThe first Param has the same effect as the ForModel one.\n\nThe last Param defines the usage of this Property.\n\nShould it be included into a Select Statement =\u003e Column exists\n\nShould it be excluded from Select Statement =\u003e Column does not exist but will be added by Statement\n\nIn both cases, if the Column exists in the result stream, it will be tried to deserialized into the type that the Property defines. If this is an implementation or IEnumerable\u003cT\u003e\n\t, the result should also be formatted as list.\n\n\t# Attributeless Configuration\n\tAs suggested from user Paulo Zemek, I modified the Reflection only MetaData API to support runtime manipulation of the Metadata.\n\n\tTo configurate any object, you have to instantiate a Config class. It acts as an Fassade to the internal API.\n\n\tTo extend the reflection based behavior, you have to call the SetConfig method on any Config instance. In the given callback, you have access to several methods that will add the attribute information like ForModel and so on. All helper methods are using the 3 base methods:\n\n\t```C#\n\tpublic void SetPropertyAttribute\u003cTProp\u003e\n\t\t(Expression\u003cFunc\u003cT, TProp\u003e\u003e exp, DataAccessAttribute attribute)\n{\n\tvar classInfo = config.GetOrCreateClassInfoCache(typeof(T));\n\tvar info = ConfigHelper.GetPropertyInfoFromLabda(exp);\n\tvar fod = classInfo.GetOrCreatePropertyCache(info);\n\tfod.AttributeInfoCaches.Add(new AttributeInfoCache(attribute));\n}\n```\n\n```C#\npublic void SetMethodAttribute\u003cTProp\u003e(Expression\u003cFunc\u003cT, TProp\u003e\u003e exp, DataAccessAttribute attribute)\n{\n\tvar classInfo = config.GetOrCreateClassInfoCache(typeof(T));\n\tvar info = ConfigHelper.GetMehtodInfoFromLabda(exp);\n\tvar fod = classInfo.MethodInfoCaches.First(s =\u003e s.MethodName == info);\n\tfod.AttributeInfoCaches.Add(new AttributeInfoCache(attribute));\n}\n```\n\n```C#\npublic void SetClassAttribute(DataAccessAttribute attribute)\n{\n\tvar classInfo = config.GetOrCreateClassInfoCache(typeof(T));\n\tclassInfo.AttributeInfoCaches.Add(new AttributeInfoCache(attribute));\n}\n```\nYou could use these methods directly to add data to the internal ConfigStore or the helper one:\n\n```C#\npublic void SetForModelKey\u003cTProp\u003e(Expression\u003cFunc\u003cT, TProp\u003e\u003e exp, string value)\n{\n\tSetPropertyAttribute(exp, new ForModel(value));\n}\n```\n\nIn one of the next releases, I will provide you a way for loading and store all these data in XML. All type information can be accessed by using the static methods in the Config class. That would allow you to reuse the type information.\n\nAll type access parts as ThreadSave.\n\nThere are two ways in managing configs:\n\n- From Outside\n\nYou can call anywhere in your code:\n\n```C#\nnew Config().SetConfig\u003cT\u003e(s =\u003e { ... })\n```\nThis allows you to configurate a well known POCO in all ways. The generated information will be added to the LocalConfig Store.\n\n- From Inside\n\nHurray! A new Attribute is there! The ConfigMehtodAttribute. You can decorate a static method with its attribute that will take a Config instance and then it allows you to configurate yourself inside the class itself.\n\n### Speed Test\nLately, I was evaluating YAORM against other ORM's with Frans Bouma's RawBencher. I recognize that the current version has some extremely critical problems with some ... let's call it \"Non optimal POCO\" usage. As YAORM depends heavily on a ADO.NET conform constructor and only uses Reflection as some kind of fallback method, this way was extremely slow. In its test, it took about 6,000 ms to enumerate all 31465 entries. That was darn slow compared to EntityFramework, and don't even mention Dapper ;-).\n\nSo I made some major improvements to these POCOs that are not self containing and ADO.NET Constructor.\n\n\u003e ADO.NET Constructor:\n\u003e\n\u003e I was talking about an Ado.net conform Ctor. This kind of Constructor is defined by an POCO and takes an instance of IDataReader | IDataRecord and reads all necessary fields from the result set and then sets and/or converts these values to its properties.\n\nAfter I made the changes to the existing code, including auto code creation due Runtime and the usage of compiled lambdas instead of the heavy usage of the reflection API, I was extremely surprised. From 6,000 ms down to 320 ms. With this test, I also made some improvements and changes to the new Config API like:\n\n### Static Factory setting\nMultibe pre-defined setter for Attributes on Properties\nControl over the InMemory ADO.NET Ctor creation\n\n# Internal Reflection\nThe ORM uses an Internal Reflection/IL/Expressions/CodeDom provider to generate most of the needed code due runtime.\n\nThere is a mixture of these technologys because some parts where just to timeconsuming to be implimented in IL. That is true for the CodeDOM part which are used to generate an Constructor due Runtime to load entitys. This was first used only by the EntityCreator but then also modifyed to be called due runtime. All reflection based work is located inside the MetaAPI and derived for the ORM.\n\n\u003e The MetaAPI uses IL and Expressions to compile accessors for Propertys and Methods. Methods are wrapped into an IL DynamicMethod and propertys are wrapped in Expressions\n\nIn future the basic Reflection API (MetaAPI) will may be moved to an very own Assambly because it is desgined to be generic. The most basic store to access everything is the \n\n```C#\npublic class MetaInfoStore\u003cTClass, TProp, TAttr, TMeth, TCtor, TArg\u003e : \n\tIDisposable\n\twhere TClass : class, IClassInfoCache\u003cTProp, TAttr, TMeth, TCtor, TArg\u003e, new()\n\twhere TProp  : class, IPropertyInfoCache\u003cTAttr\u003e, new()\n\twhere TAttr  : class, IAttributeInfoCache, new()\n\twhere TMeth  : class, IMethodInfoCache\u003cTAttr, TArg\u003e, new()\n\twhere TCtor  : class, IConstructorInfoCache\u003cTAttr, TArg\u003e, new() \n\twhere TArg   : class, IMethodArgsInfoCache\u003cTAttr\u003e, new()\n```\nAs is said it is desgined to be generic and reusable. It contains a class to convert an Type instance to an instance of TClass by using the GetOrCreateClassInfoCache method. This method is of course also Recusiv and aware of that, it will ether give you an instance from the local store or enumerates all \"Most used Infos\". That means it will enumerate throu all Propertys, Methods, Arguments, Constructors and Attributes on each of them and store them. This class is optional ThreadSave by using the EnableThreadSafety property. This optional property was introduced to ensure a maximum of Performance.\n\nThis class can be ether Global or InstanceLocal. By using the constructor\n\n```C#\npublic MetaInfoStore(bool isGlobal)\n```\nYou can spezify that. To ensure a maximum of Performance you can also Impliment for example the IPropertyInfoCache and override the Init mehtod to define new Attributes that are common accessed. This brings a huge performance advance because otherwise you have to loop through the collection of all Attributes to find the desired one what, of course is timeconsuming. Take a look into the DbPropertyInfoCache to see examples.\n\nAn other good reason to use this, is the advantage of adding \"fake\" propertys and Attributes due Runtime by simply adding them to the collections. This feature is used by the ConfigAttribute to extend POCOs. Each part of the YAORM is using this Store and if you add a new Property to it, it will find it. For example the MethodInfoCache is implimenting an Constructor:\n\n```C#\ninternal MethodInfoCache(Func\u003cobject, object[], object\u003e fakeMehtod, string name = null, params TAtt[] attributes)\n```\nThis allows you to add each method you want to each class without using .net Tricks such as dynamic's.\n\n# LocalDbRepository\nIts an Collection that will enforce ForginKeyDeclarationsAttributes in future also ForginKeyAttributes. With this class you can define local Databases inside a scope. All \"tables\" inside this scope will be validates if you add any object to it and if you try to add an Entity to it which would violate ForeignKey's an exception is thrown.\n\nFirst you have to setup an DatabaseScope\n\n```C#\nusing (new DatabaseScope())\n{\n\n}\n```\nThis scope will be an Container and validates multibe Tables that are defined inside the Scope. This syntax was takes from the TransactionScope that exists within the .netFramework. Then you have to define tables by creating them inside the scope\n\n```C#\nusing (new DatabaseScope())\n{\n\t_books = new LocalDbReposetory\u003cBook\u003e();\n\t_images = new LocalDbReposetory\u003cImage\u003e();\n}\n```\nThe defintion for Book and Image is folloring:\n\n```C#\npublic class Image\n{\n\t[PrimaryKey]\n\tpublic long ImageId { get; set; }\n\n\tpublic string Text { get; set; }\n\n\t[ForeignKeyDeclaration(\"BookId\", typeof(Book))]\n\tpublic int IdBook { get; set; }\n}\n```\n\n```C#\npublic class Book\n{\n\t[PrimaryKey]\n\tpublic int BookId { get; set; }\n\n\tpublic string BookName { get; set; }\n}\n```\n\nIt is important to decorate an PrimaryKeyAttribute and also an ForeignKeyDeclarationAttribute to define valid connections between both Tables. You can ether use Attributes or an Config method (s.a). The first argument on the ForgeinKeyDeclarationAttribute will be soon obsolete. You can use the Constructor of the LocalDbReposetory to define an PrimaryKey generator if you use PrimaryKeys that are not of type of Long, Int, Guid or if you want to define other Autoincriment by 1 and starting with 1.\n\n## Version 2.0.180\n\n\n### Trigger\nIn the latest version you can hook all DDL triggers (MsSQL) on a local collection. Supported are:\n- WITH REPLICATION\n- WITHOUT REPLICATION\n\nThen on both\n\n- AFTER\n- BEFORE\n- INSTEAD OF\n\nThen on all\n\n- INSERT\n- UPDATE\n- DELETE\n\nFrom LocalDbTriggerTestNotInReplication:\n\n```C#\nLocalDbRepository\u003cUsers\u003e repro;\nusing (var db = new DatabaseScope())\n{\n\trepro = new LocalDbRepository\u003cUsers\u003e(new DbConfig());\n}\nvar orderFlag = false;\nrepro.Triggers.NotForReplication.For.Insert += (sender, token) =\u003e\n{\n\tAssert.That(orderFlag, Is.False);\n\torderFlag = true;\n};\nrepro.Triggers.NotForReplication.After.Insert += (sender, token) =\u003e\n{\n\ttoken.Cancel(\"AFTER\");\n};\nAssert.That(orderFlag, Is.False);\nAssert.That(() =\u003e\n{\n\trepro.Add(new Users());\n}, Throws.Exception.InstanceOf\u003cITriggerException\u003e().With.Property(\"Reason\").EqualTo(\"AFTER\"));\nAssert.That(orderFlag, Is.True);\nAssert.That(repro.Count, Is.EqualTo(0));\n```\n\n## Constraints\n\nAs there are trigger there are also Constraints you can add to any Table.\n\nAll Contraints have to be added due creation of an database. That means you must use the example code in the DatabaseScope. This restriction was made to enforce that all Entities always match the given constrains.\n\nThere is support for:\n\n- Check\n  - Adds a check that will be enforced when an Item is Inserted or Updated\n- Unique\n  - Adds a check that will be enforced when an Item is Inserted or Updated\n- Defaults\n  - Adds a check that will be enforced when an Item is Inserted or Updated\n\nFrom LocalDbWithConstraintsTest:\n\n```C#\npublic LocalDbRepository\u003cImage\u003e TestInit(IEnumerable\u003cILocalDbCheckConstraint\u003cImage\u003e\u003e checks,\n\t\t\tIEnumerable\u003cILocalDbUniqueConstraint\u003cImage\u003e\u003e unique,\n\t\t\tIEnumerable\u003cILocalDbDefaultConstraint\u003cImage\u003e\u003e defaults)\n{\n\tLocalDbRepository\u003cImage\u003e images;\n\tusing (new DatabaseScope())\n\t{\n\t\timages = new LocalDbRepository\u003cImage\u003e(new DbConfig());\n\t\tif (checks != null)\n\t\t\tforeach (var localDbCheckConstraint in checks)\n\t\t\t{\n\t\t\t\timages.Constraints.Check.Add(localDbCheckConstraint);\n\t\t\t}\n\t\tif (unique != null)\n\t\t\tforeach (var localDbCheckConstraint in unique)\n\t\t\t{\n\t\t\t\timages.Constraints.Unique.Add(localDbCheckConstraint);\n\t\t\t}\n\t\tif (defaults != null)\n\t\t\tforeach (var localDbCheckConstraint in defaults)\n\t\t\t{\n\t\t\t\timages.Constraints.Default.Add(localDbCheckConstraint);\n\t\t\t}\n\t}\n\treturn images;\n}\n\n[Test]\npublic void AddCheckConstraint()\n{\n\tvar images = TestInit(new[]{new LocalDbCheckConstraint\u003cImage\u003e(\"TestConstraint\", s =\u003e\n\t{\n\t\tvar item = s;\n\t\treturn item.IdBook \u003e 0 \u0026\u0026 item.IdBook \u003c 10;\n\t})}, null, null);\n\n\tvar image = new Image();\n\timage.IdBook = 20;\n\tAssert.That(() =\u003e images.Add(image), Throws.Exception.TypeOf\u003cConstraintException\u003e());\n\timage.IdBook = 9;\n\tAssert.That(() =\u003e images.Add(image), Throws.Nothing);\n\tAssert.That(images.Count, Is.EqualTo(1));\n}\n```\n\nNote:\nThere are implementations for all 3 constraints. For the Default constraint there are 2:\n- LocalDbDefaultConstraint\u003cTEntity, TValue\u003e\n- LocalDbDefaultConstraintEx\u003cTEntity, TValue\u003e\n\nLocalDbDefaultConstraint: Will always update the value no matter what value was inside the entitie\n\nLocalDbDefaultConstraintEx: Will check the value for its Default(by using C# default() operator) and if its not equals the default value it will set an predefined value\n\t\n\n# Entity Creator\nThe lib now contains a Console Application that will be possible to create Entities based on a database. At the Current state (01.Nov.2014), only MsSql databases are supported and the testing is very basic.\n\nThe usage is simple in its basic component but has a lot of potential. And also, the idea here is to re-write the current CommandoLine tool to support complete parameterised works.\n\nAfter you start the program, it will ask you for a Target directory (where the generated files will be stored) and a connection string.\n\n\n\nAfter that, you will see some information from that database including Tables, StoredProcedures and Views. Views are handled the same as Tables are because the calling syntax is pretty much the same.\n\nWith typing a Number of a Table, Sp or View, you can alter the settings of that object. Other commands are:\n\n\\compile\n\\autoGenNames\n\\add\nYou start the process:\n\nStarts the compiling of all Tables, SPs and views that are not excluded\nStarts a simple renaming process that will Save Remove all '_',' ' chars from the database names and replacing them with C# Conform names\nNot implemented (In future, it will be possible to add static loader constructors. This will dramatically increase the selecting performance. But due to the newest feature (XML based loading), this is not completely implemented).\nChanges in Version 2.0\n\nMore Unit tests (yeeea)\n- Mapping from DB fields to Class properties is now stored inside the ClassInfoCache and is persisted\n- The Reflection API now uses HashSets instead of lists\n- DataConverterExtentions are reduced\n- PropertyInfoCache is now used to access Properties directly by using dynamic compiled Lambdas\n- A Static factory method Delegate on ClassInfoCache level is now taking care of the creation of POCOs\n- Some methods from the EntityCreator are moved from the EXE to the DataAccess.dll\n- A new class \"FactoryHelper\" is now capable of creating ADO.NET Ctor due Runtime by using the improved methods of the EntityCreator\nMajor improvements in ctor creation the EntityCreator and the Runtime creator are now capable of constructors for:\n  - (Single)XML\n  - (List)XML\n  - (Single)ForginKey\n  - (List)ForginKey\n  - ValueConverter\n  - Null Values\n  - (Possible)Null Values\n  - ForModel\n  - Added Multibe Comments\n  - Removed the Linq Provider completely\n  - Replaced the ReposetoryCollection with the DbCollection\n  - Bug fixing\n \n# Points of Interest\nThis project has brought me a lot of fun and one or two sleepless nights and I guess they will not be the last I had because of this. The lib contains a small Linq Provider that is marked as obsolete because, due to the implementation and development, I was ... let's say I was annoyed by Linq.\n\nI expect from this project to have some ideas and more to improve my work.\n\nThanks to everyone that took the time to read this. Thanks also to my trainer Christian H. for his impressions and help.\n","funding_links":["https://github.com/sponsors/JPVenson"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjpvenson%2Fdataaccess","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjpvenson%2Fdataaccess","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjpvenson%2Fdataaccess/lists"}