Quick Start
What is ORM for?
Relational vs. Object Representation of Data: What is the difference?
- SQL databases stores data in a relational way into tables (you can imagine some spreadsheets like well known Excel for example).
- Table cells can only have primitive data types like any kind of number, truth value (boolean or bit), text strings, datetimes, etc.
- So, if you want to bind 2 tables that one depends on the other or somehow contains (aggregates) the other, you make relations between those tables by equality of values of some foriegn key and the other table's primary key (a key which contains a unique value in frame of the table).
- In object oriented programming, the programmer is abstracted from the logic of referencing (pointing) to an object and it is no problem to aggregate an object by declaring a "pointer" to a child object inside a parent object. The child object can also have such pointers to its children. You can aggregate into unlimited depth with multiple aggregates of different types on each level (as you like) and you make then some object trees (remember that phrase).
- If you join tables using some SQL query, you only extends the number of columns in a query result - Each table row will have additional columns for each joined table, we say that it is a flat table (data) select.
So, what should an ORM be responsible for?
- ORM should map the values from SQL query results into object entities and form the object tree in the correct way (aggregate objects to correct parents at a correct tree level) from the flat table data select.
- ORM should also be responsible for storing and updating the data.
- ORM should also generate entity classes.
Let's Start
- Create a database with single column primary key tables. Use the same id column name convention for all the tables.
- The data type of PK can be int32, int64 or string. Id must be auto-increment in all tables or you have to set ID3Context.UseAutoIncrement to false for all tables.
- Generate Entities... (Using DDD) Create the domain layer with "Entities" and "Repositories" folders.
- (Optionally) Define the aggregates of the SQL relations (into the EntitiesFromEFCore.json) or remove the file to persist all navigation properties...
- Option 1: Run EF Core database-first scaffold command in Nuget Package Manager Console for generating the entity classes, then update EntitiesFromEFCore.tt script paths and names and run it to generate D3ORM entity classes.
- Option 2: ...or write CSharp classes for database entities by your own way following a few rules.
- Repository Interfaces...
- Option 1: Generate repository interfaces by Repositories-Ifaces.tt - it will generate repository interfaces that extend ICommonRepository<TEntity> or IAggRootRepository<TEntity>. You will then need to include KLO128.D3ORM.Common.Abstract assembly.
- Option 2: ...or use adaptation pattern for the repository implementations and the interfaces do not have to extend anything. Do not use this option, if you have a data layer in a single library, because you will have to include D3ORM libraries anyway, so you can save some coding by the Option 1.
- Create an infrastructure layer (or a data layer implementation), update and run EntityPropMappings.tt, then implement repository adaptations or run Repositories-Impl.tt - repository classes will then extend D3CommonRepository<TEntity> or D3AggRootRepository<TEntity>.
- Create an application layer (or a service layer), update and run EntityDTOs.tt.
- (Optionally) Define EntityDTOs.json rules to generate DTO classes.
- Hint: Keep your query specifications prebuilt and static or singleton. You can create IQueryContainer to use the query specifications in the services with a scoped life time and with a possibility to have more implementations.
- Try to minimize updating of queries in each request. Rather build queries with all filters during the startup (if possible).
- Create test libraries and the presentation layer.