Plinth.Scaffold
1.0.11
Prefix Reserved
See the version list below for details.
dotnet tool install --global Plinth.Scaffold --version 1.0.11
dotnet new tool-manifest # if you are setting up this repo dotnet tool install --local Plinth.Scaffold --version 1.0.11
#tool dotnet:?package=Plinth.Scaffold&version=1.0.11
nuke :add-package Plinth.Scaffold --version 1.0.11
Plinth Scaffold
Overview
Plinth Scaffold is a productivity tool that is used to quickly generate boilerplate code for CRUD operations around a project's business entities. It is primarily meant to be used with the Plinth Common Libraries as well as the Plinth API Starter project, but can also be extended to more specific use-cases if desired. It accepts a JSON file as an input, which defines all business entities of the project, including specific fields and any special behaviors. The output contains generated code at every level of a .NET Core API project, including: SQL table definitions, SQL stored procedures, C# common models, data access classes, logic classes, controller classes, C# API models, and a C# API client. Optionally, this tool can also generate iOS Swift API models and client, Java Retrofit API models and client, as well as Typescript models.
Running Scaffold
Scaffold is installed and ran as a Nuget tool, which can be installed via dotnet.exe. The general syntax for running the Scaffold tool via command-line is the following:
dotnet scaffold [input_file_path] [arguments]
The following example will create the dotnet tool manifest in your project, update Scaffold to the latest available version on nuget.org, and run the tool using a local scaffold.json
file as input, and the current folder as output.
@ECHO OFF
IF NOT EXIST .config/dotnet-tools.json (
ECHO Creating dotnet tool manifest...
dotnet new tool-manifest
)
dotnet tool update Plinth.Scaffold
dotnet scaffold scaffold.json -o "."
PAUSE
Command-line Arguments
Scaffold supports the following optional command-line arguments:
--help
- display help screen--version
- display version information-o, --output
- change where output files are written--disable-database
- disable generation of database entities--disable-common
- disable generation of common entities--disable-dataaccess
- disable generation of data access entities--disable-logic
- disable generation of business logic entities--disable-webapi
- disable generation of web api entities--webapi-client
- generate C# client for web api--web
- generate clients for web--mobile-android
- generate clients for Android mobile platform (Java)--mobile-ios
- generate clients for iOS mobile platform (Swift)--schema
- generate json schema for scaffold input file--ignore-cycle-errors
- do not throw an error is a cycle is detected in foreign key definitions-q, --quiet
- suppress all output-v, --verbose
- output scaffolding info
Input File
Scaffold generates its code using a JSON file as an input, which outlines the entire project definition, settings, data model entities and their relationships. Below is a sample of the input file which demonstrates the main sections of the input. Subsequent sections of this document will go into more detail on all available settings and discuss different features supported by the tool.
{
"name": "TestProject",
"cSharpNamespace": "Test.Project",
"database":
{
"generateIndividualEntityFiles": true
},
"enums": [
{
"name": "RoleType",
"values": [
"User",
"Admin"
]
}
],
"entities": [
{
"name": "User",
"pluralName": "Users",
"fields": [
{
"name": "UserID",
"type": "Long",
"isPrimaryKey": true
},
{
"name": "GUID",
"type": "Guid",
"isApplicationPrimaryKey": true
},
{
"name": "Username",
"type": "String",
"isUnique": true
},
{
"name": "Role",
"type": "Enum",
"enumName": "RoleType"
},
{
"name": "DateCreated",
"type": "DateTime",
"isCurrentDateTime": true
}
]
}
]
}
Root Settings
Name | Type | Default | Description |
---|---|---|---|
name | string | - | Name of the project. |
cSharpNamespace | string | - | Root namespace of the generated C# classes. |
javaPackage | string | - | Java package name of the generated Android (Java) files. |
dbms | Enum <ul><li>MSSQL</li><li>PGSQL</li></ul> | MSSQL | DBMS syntax of the generated database files. MSSQL is the default and has the most feature support at the moment. |
databaseConnector | Enum <ul><li>Plinth</li><li>Dapper</li></ul> | Plinth | Database library used in the generated data access classes (DAO) for connecting to the database, and mapping parameters and result sets. Plinth is the default and has the most feature support at the moment. |
databaseNamespace | string | - | Namespace of the data access classes when referenced from other generated C# classes. This setting is only used when a custom data access layer needs to be referenced from the generated files, which is usually not the case. By default, the data access namespace will be generated as {cSharpNamespace}.DataAccess.Database . |
usePlinthCommon | bool | true | When true, the Plinth Common Libraries namespace will be referenced for utility methods in generated C# classes.<br><br>When false, the project's root namespace will be referenced instead. |
useExplicitTypes | bool | false | When true, explicit types will be used when defining local variables in generated C# classes.<br><br>When false, local variable types will be defined implicitly using the var keyword. |
useNullableReferenceTypes | bool | false | When true, nullable reference types will have the nullable operator ? appended to them.<br><br>When false, only the nullable value types will use the nullable operator. |
useMicrosoftDataSqlClient | bool | false | When true, data access code will use Microsoft.Data.SqlClient for communicating with the database.<br><br>When false, System.Data.SqlClient will be used instead. |
useJwt | bool | false | When true, Plinth API security code will use the JWT implementation of the security token.<br><br>When false, custom Plinth implementation of the security token will be used instead. |
useSwaggerAnnotations | bool | false | When true, Swagger Swashbuckle.AspNetCore.Annotations will be used in C# API models for additional field context, such as designating read-only fields. |
loggingFramework | Enum <ul><li>CommonLogging</li><li>MicrosoftLogging</li></ul> | CommonLogging | Logging library used in the generated C# classes. |
useInjectedLogger | bool | false | When true, the configured logger (specified by the loggingFramework setting) will be injected as a dependency in C# class constructors.<br><br>When false, a static logger is used via StaticLogManager.GetLogger() . |
useBaseFolderStructure | bool | true | When true, generated code will be placed in a Base folder on every level (database, data access, logic, etc) and configured for extension and overrides. This allows the Scaffold tool to be re-runnable by cleaning the Base folders on each run and re-generating all code. All custom extensions will be preserved since they are done in separate files and folders. See "Extending Generated Code" section for more details.<br><br>When false, generated code will be placed in the same folders as custom code, requiring custom extensions to be applied directly to the generated files. Because of this limitation, base folder structure is commonly enabled in recent projects. |
useRowLevelSecurity | bool | false | When true, stored procedures will include pre-operation validation checks to make sure that the calling user has access to INSERT , UPDATE , DELETE , and SELECT the desired entity. See "Row-Level Security" section for more details. |
systemCallingUserName | string | - | The identifier of the System user that is passed as the CallingUser parameter of generated stored procedures. This is used in row-level security validations for bypassing user-specific security checks, since a System user should have access to all entities of the application. |
generateDataAccessInterfaceScaffolds | bool | false | When true, generated data access classes (DAOs) will also have a corresponding interface generated for them in order to make unit testing easier through a mock data layer. |
generateWebApiClientScaffolds | bool | false | When true, a C# client for web api will be generated. |
generateWebScaffolds | bool | false | When true, a client for web (Typescript) will be generated. |
generateMobileAndroidScaffolds | bool | false | When true, a client for Android mobile platform (Java) will be generated. |
generateMobileiOSScaffolds | bool | false | When true, a client for iOS mobile platform (Swift) will be generated. |
generateBulkInsertMethods | bool | false | When true, methods for inserting lists of entities will be generated in addition to single-record inserts. This is done through the use of table-valued parameters in the bulk insert stored procedures. |
generateModelColumnAnnotations | bool | false | When true, System.ComponentModel.DataAnnotations.Schema will be used in C# common models for annotating database column names on model fields. |
disableAuditFields | bool | false | When true, database audit fields (DateInserted , InsertedBy , DateUpdated , UpdatedBy ) will not be generated. |
exposeAuditFields | bool | false | When true, database audit fields (DateInserted , InsertedBy , DateUpdated , UpdatedBy ) will be exposed in C# common and API models. |
database | DatabaseSettings | - | Database-related settings. See "Database Settings" section for more details. |
enums | List<EnumSettings> | - | List of project Enums and their values. See "Enum Settings" section for more details. |
entities | List<EntitySettings> | - | List of project entities and their settings. See "Entity Settings" section for more details. |
Database Settings
Name | Type | Default | Description |
---|---|---|---|
tablesFileName | string | - | When generateIndividualEntityFiles is set to false, this will be the name of the single sql file that contains all table definitions. Example: Tables.sql |
proceduresFileName | string | - | When generateIndividualEntityFiles is set to false, this will be the name of the single sql file that contains all stored procedure definitions. Example: Procedures.sql |
generateIndividualEntityFiles | bool | false | When true, generated database files will be split per entity. For example, if a project contains 8 entities, 8 .sql files will be generated for table definitions, one per each table. 32 .sql files will be generated for stored procedure definitions (8 entities multiplied by 4 stored procedures per entity).<br><br>When false, a single file will be generated for all table definitions and a single file will be generated for all stored procedure definitions. |
generateSsdtFiles | bool | false | When true, DacFx library will be used for generating an SSDT database project that includes a merger or all generated and custom database code in the database folder. This project can then be used for automated database deployment. A .dacpac file is also created in this process, and can also me used for deploying schema changes. |
ssdtSqlServerVersion | Enum <ul><li>Sql90</li><li>Sql100</li><li>SqlAzure</li><li>Sql110</li><li>Sql120</li><li>Sql130</li><li>Sql140</li><li>Sql150</li><li>SqlDw</li><li>Sql160</li></ul> | Sql150 | When generateSsdtFiles is set to true, this will be the version of SQL Server used for generating the SSDT database project and .dacpac file. |
msSqlSchemaName | string | dbo | Custom schema name to be used for generated MSSQL database files. |
pgSqlSchemaName | string | public | Custom schema name to be used for generated PGSQL database files. |
Enum Settings
Name | Type | Default | Description |
---|---|---|---|
name | string | - | Name of the Enum. Referenced by an entity field's enumName setting when the entity field's type is Enum . |
forceApiEnumGeneration | bool | false | By default, Enums that are not referenced by any entity fields will not have an API definition generated for them. When this is set to true, an API definition will be generated for this Enum regardless of entity references. This is useful when needing to generate an API definition for an Enum that is not directly tied to the data model. |
values | List<string> | - | Values of the Enum. |
Entity Settings
Name | Type | Default | Description |
---|---|---|---|
name | string | - | Name of the entity. |
pluralName | string | - | Plural name of the entity. Used when generating code and documentation that requires referring to the entity in a plural context. |
abbreviatedName | string | - | The abbreviated name of the entity that will be as the table alias in generated stored procedures. By default, the abbreviated name is generated using the first letter of every word in the entity's name . |
superclassName | string | - | Name of the class that the entity's generated models should extend. This is only used if the project has a custom base class than needs to be the superclass of the generated models. |
msSqlSchemaName | string | - | Custom schema name to be used for generated MSSQL database files for this entity. |
pgSqlSchemaName | string | - | Custom schema name to be used for generated PGSQL database files for this entity. |
rowLevelSecurityParent | string | - | When useRowLevelSecurity is set to true, this specifies the name of the entity from which the current entity inherits its row-level security definition. See "Row-Level Security" section for more details. |
rowLevelSecuritySelectSqlCondition | string | - | An optional SQL statement that will be added as a condition to SELECT stored procedure row-level security code. |
rowLevelSecurityModifySqlCondition | string | - | An optional SQL statement that will be added as a condition to INSERT , UPDATE , and DELETE stored procedure row-level security code. |
disableRowLevelSecuritySelectSqlGeneration | bool | false | When true, row-level security code will not be generated in the SELECT stored procedure for the entity. This is useful when creating entities that allow public reading of data. |
forceApiModelGeneration | bool | false | By default, entities that have controller generation disabled will not have a C# API model generated for them. When this is set to true, C# API model will be generated for this entity regardless of controller generation settings. This is useful for generating C# API models for custom controllers. |
disableCommonModelGeneration | bool | false | When true, C# common models will not be generated for this entity. Setting this to true will automatically set disableDAOGeneration , disableManagerGeneration , disableControllerGeneration , and disableApiModelGeneration to true as well. |
disableDAOGeneration | bool | false | When true, data access classes will not be generated for this entity. Setting this to true will automatically set disableManagerGeneration , disableControllerGeneration , and disableApiModelGeneration to true as well. |
disableManagerGeneration | bool | false | When true, logic classes will not be generated for this entity. Setting this to true will automatically set disableControllerGeneration , and disableApiModelGeneration to true as well. |
disableControllerGeneration | bool | false | When true, controller classes will not be generated for this entity. Setting this to true will automatically set disableApiModelGeneration to true as well. |
disableApiModelGeneration | bool | false | When true, C# API models will not be generated for this entity. |
disableSearchApiGeneration | bool | false | When true, Search endpoints will not be generated in controllers for this entity. |
disableGetApiGeneration | bool | false | When true, Get endpoints will not be generated in controllers for this entity. |
disableCreateListApiGeneration | bool | false | When true, CreateList endpoints will not be generated in controllers for this entity. |
disableCreateApiGeneration | bool | false | When true, Create endpoints will not be generated in controllers for this entity. |
disableUpdateApiGeneration | bool | false | When true, Update endpoints will not be generated in controllers for this entity. |
disableDeleteApiGeneration | bool | false | When true, Delete endpoints will not be generated in controllers for this entity. |
disableReferencedEntityApiGeneration | bool | false | When true, Get and Create endpoints for this entity will not be generated in controllers for entities that this entity references through foreign key definitions. |
disableReferencingEntityApiGeneration | bool | false | When true, Get and Create endpoints for entities that reference this entity through foreign key definitions will not be generated in controllers for this entity. |
generateBulkInsertMethods | bool | false | When true, methods for inserting lists of entities will be generated in addition to single-record inserts for this entity. This is an entity-specific equivalent of the root generateBulkInsertMethods setting. |
disableAuditFields | bool | false | When true, database audit fields (DateInserted , InsertedBy , DateUpdated , UpdatedBy ) will not be generated for this entity. This is an entity-specific equivalent of the root disableAuditFields setting. |
exposeAuditFields | bool | false | When true, database audit fields (DateInserted , InsertedBy , DateUpdated , UpdatedBy ) will be exposed in C# common and API models for this entity. This is an entity-specific equivalent of the root exposeAuditFields setting. |
isSystemEntity | bool | false | When useRowLevelSecurity is set to true, this specifies that this entity can only be accessed by the System calling user. See "Row-Level Security" section for more details. |
isCallingUserIdentity | bool | false | When useRowLevelSecurity is set to true, this specifies that this entity's GUID represents the identifier of the CallingUser of the current request context. Most typically this is the User entity, and functions as the top-level rowLevelSecurityParent . See "Row-Level Security" section for more details. |
supportsSoftDelete | bool | false | When true, an IsDeleted flag column will be added to the SQL table generated for this entity, and the Delete stored procedure will set the IsDeleted flag instead of deleting the entire row. Search stored procedure will also filter-out records with IsDeleted set. |
fields | List<EntityField> | - | A list of all entity fields that make up this entity. See "Entity Field Settings" section for more details. |
sortFields | List<SortField> | - | An optional sort field list that specifies the sort order of the Search stored procedure results for this entity. See "Sort Field Settings" section for more details. |
Sort Field Settings
Name | Type | Default | Description |
---|---|---|---|
name | string | - | Name of the sort field. References an entity field's name setting. |
sortDirection | Enum <ul><li>Desc</li><li>Asc</li></ul> | Desc | Sort direction of the sort field. |
Entity Field Settings
Name | Type | Default | Description |
---|---|---|---|
name | string | - | Name of the entity field. |
type | Enum <ul><li>Bool</li><li>Enum</li><li>Guid</li><li>Char</li><li>String</li><li>ShortString</li><li>LongString</li><li>Text</li><li>Int</li><li>Long</li><li>Decimal</li><li>Money</li><li>Float</li><li>Date</li><li>Time</li><li>DateTime</li><li>DateTimeOffset</li><li>Binary</li><li>Point</li><li>List</li><li>JsonObject</li><li>Custom</li></ul> | - | Data type of the entity field. See "Entity Field Type Conversion" section for more details. |
defaultValue | string | - | An optional default value of the entity field. |
isPrimaryKey | bool | false | Specifies whether this field is the primary key for the entity. This field will be used as the database primary key for foreign keys and joins. |
isApplicationPrimaryKey | bool | false | Specifies whether this field is the application primary key for the entity. An application primary key is used in stored procedure parameters and results, as well as all layers above (C# code, API clients) to reference the entity. Typically it is a of type Guid in order to not leak any information at the API by exposing auto-increment integer fields, for example. |
isUnique | bool | false | Specifies whether this field is unique among all records for the entity. Setting this to true will automatically add a unique constraint in the generated SQL table definition as well as include this field in the generated Search code parameters. Unique fields will also have specific GetBy methods generated for them in order to look up a single record by this field's value. For example, if a User entity has a unique Username field, a GetUserByUsernameAsync method will be generated in C# controllers, logic, and data access classes. |
additionalUniqueFields | List<string> | - | In cases when an entity's unique constraint should be specified through a composite unique key of fields, this list of additional entity field name values can be provided. The GetBy methods will still be generated in this case, and will include every field that makes up composite unique key. |
isNullable | bool | false | Specifies whether this field is allowed to have null values. This affects SQL table definition and stored procedure joins (INNER JOIN for non-nullable and LEFT OUTER JOIN for nullable fields). |
isDbOnly | bool | false | Specifies whether this field is internal to the database and should not be exposed at the application layer. |
isEncrypted | bool | false | Specifies whether this field should be encrypted when stored in the database. When true, the Plinth Common Libraries ISecureData utility will be used to encrypt and decrypt this field in the generated data access class. |
isSearchField | bool | false | Specifies whether this field should be included in the generated Search code parameters. Setting this to true will not create a database index. |
hasIndex | bool | false | Specifies whether this field should have a database index generated for it. Setting this to true will automatically include this field in the generated Search code parameters. |
hasUniqueIndex | bool | false | Specifies whether this field should have a database unique index generated for it. Fields with a unique index are treated like fields with isUnique set to true in terms of the code that gets generated. |
hasSpatialIndex | bool | false | Specifies whether this field should have a database spatial index generated for it, in cases when this field represents a spatial column. Currently only type Point is supported. |
additionalIndexFields | List<string> | - | In cases when an entity's index should be specified through a composite index of fields, this list of additional entity field name values can be provided. |
isCallingUserGuid | bool | false | Specifies whether this field represents the id (or Guid) of the CallingUser who inserted the record. Setting this to true will automatically set this field's value to the CallingUser 's GUID when inserting a new record in the generated data access classes. |
isCurrentDateTime | bool | false | Specifies whether this field represents the current date and time of when the record was inserted. Setting this to true will automatically set this field's value to DateTime.UtcNow when inserting a new record in the generated data access classes. |
isBlobGuid | bool | false | Specifies whether this field represents the id (or Guid) of BLOB data. BLOB fields will have upload and download endpoints added for them in the generated controllers, as well as include additional business logic code to manage BLOBs using the Plinth.Storage Library. |
isWebApiHidden | bool | false | When true, this field will not be included in the entity's generated C# API models. This setting is used for specifying internal data fields that should not be exposed at the API layer. |
enumName | string | - | When type is Enum , this setting references an Enum's name settings for specifying the Enum type of this field. |
isUnicode | bool | false | When type is Char , String , ShortString , LongString , or Text , this setting specifies whether unicode characters are allowed in the field's value. This affects the database column type by using NVARCHAR instead of VARCHAR . |
length | int | - | When type is Char , String , or Binary , this setting specifies the length of the database column type. |
listType | string | - | When type is List , this setting specifies the type of elements in the list. This can reference external types, as long as they are defined in the custom project code. List fields are stored as a Json string in the database column. |
jsonObjectType | string | - | When type is JsonObject , this setting specifies the type of the Json object. This can reference external types, as long as they are defined in the custom project code. JsonObject fields are stored as a Json string in the database column. |
customFieldType | string | - | When type is Custom , this setting specifies the type of the custom object. This can reference external types, as long as they are defined in the custom project code. |
sqlCalculationStatement | string | - | Specifies the SQL calculation statement to use when this field represents a calculated column. For example, a GEOGRAPHY::Point column can be calculated from Latitude and Longitude values by specifying this setting as GEOGRAPHY::Point(ISNULL(Latitude,0), ISNULL(Longitude,0), 4326) PERSISTED . |
foreignKeyEntityName | string | - | When this field is a foreign key, this is the name of the entity that the foreign key references. |
foreignKeyEntityAbbreviatedName | string | - | The abbreviated name of the foreign key entity that will be as the table alias in generated stored procedures. By default, the abbreviated name is generated using the first letter of every word in the entity's name . |
foreignKeyEntityFieldName | string | - | The name of the entity field that is the primary key of the entity that the foreign key references. |
foreignKeyEntityAliasFieldName | string | - | Optional custom name given to the foreign key field in stored procedure results and C# models. By default this field will be named as {ForeignKeyEntity.Name}{ForeignKeyEntityField.Name} . |
isForeignKeyOneToOne | bool | false | Specifies whether the foreign key has a 1:1 relationship, in which case this field will not be included in the generated Search code parameters. Get and Create endpoints for this entity will also not be generated in the foreign key entity's controllers. |
isForeignKeyCascadeDelete | bool | false | When true, generated database foreign key definition will include an ON DELETE CASCADE to automatically delete this entity when the foreign key entity gets deleted. |
additionalForeignKeyFields | List<AdditionalForeignKeyField> | - | Specifying a list of additional fields on the foreign key entity will return these fields in the Search stored procedure results. See "Additional Foreign Key Field Settings" section for more details. |
enableExternalUrlGeneration | bool | false | When isBlobGuid is true, setting this to true will add a new property to the generated C# models to return the url for downloading BLOB data. Currently only supports AWS S3 Plinth.Storage provider. |
enableUploadApiGeneration | bool | false | When isBlobGuid is true, setting this to true will generate a controller endpoint to upload BLOB data. |
enableDownloadApiGeneration | bool | false | When isBlobGuid is true, setting this to true will generate a controller endpoint to download BLOB data. |
enableDownloadUrlApiGeneration | bool | false | When isBlobGuid is true, setting this to true will generate a controller endpoint to retrieve a temporary url for downloading BLOB data. Uses the Plinth.Storage Library GetTemporaryUrlReferenceAsync method. |
enableLargeFileUploads | bool | false | When isBlobGuid is true, setting this to true will decorated the BLOB upload endpoint with the [DisableRequestSizeLimit] attribute to enable large file uploads. |
comment | string | - | An optional comment that will appear above the generated code for this field in table definition and common and API models. |
Additional Foreign Key Field Settings
Name | Type | Default | Description |
---|---|---|---|
name | string | - | Name of the additional foreign key field. References an entity field's name setting. |
aliasName | string | - | Optional custom name given to the foreign key field in stored procedure results and C# models. By default this field will be named as {ForeignKeyEntity.Name}{ForeignKeyEntityField.Name} . |
Entity Field Type Conversion
Entity Field Type | MSSQL Type | PGSQL Type | C# Type | Java Type | Swift Type | Typescript Type |
---|---|---|---|---|---|---|
Bool | BIT | BOOLEAN | bool | Boolean | Bool | boolean |
Enum | VARCHAR(50) | VARCHAR(50) | {enumName} | {enumName} | {enumName} | {enumName} |
Guid | UNIQUEIDENTIFIER | UUID | Guid | UUID | UUID | string |
Char | (N)CHAR({length}) <br> (N)CHAR(255) | CHAR({length}) <br> CHAR(255) | string | String | String | string |
String | (N)VARCHAR({length}) <br> (N)VARCHAR(255) | VARCHAR({length}) <br> VARCHAR(255) | string | String | String | string |
ShortString | (N)VARCHAR(50) | VARCHAR(50) | string | String | String | string |
LongString | (N)VARCHAR(1000) | VARCHAR(1000) | string | String | String | string |
Text | (N)VARCHAR(MAX) | TEXT | string | String | String | string |
Int | INT | SERIAL (isPrimaryKey = true) <br> INT | int | Integer | Int | number |
Long | BIGINT | BIGSERIAL (isPrimaryKey = true) <br> BIGINT | long | Long | Int | number |
Decimal | DECIMAL(21,12) | DECIMAL(21,12) | decimal | Double | Double | number |
Money | DECIMAL(12,2) | DECIMAL(12,2) | decimal | Double | Double | number |
Float | FLOAT | FLOAT | double | Double | Double | number |
Date | DATE | DATE | DateTime | Date | Date | Date |
Time | TIME(3) | TIME | TimeSpan | Date | Date | Date |
DateTime | DATETIME2(3) | TIMESTAMP WITH TIME ZONE | DateTime | Date | Date | Date |
DateTimeOffset | DATETIMEOFFSET(3) | TIMESTAMP WITH TIME ZONE | DateTime | Date | Date | Date |
Binary | VARBINARY({length}) <br> VARBINARY(MAX) | BIT({length}) <br> BYTEA | byte[] | byte[] | [UInt8] | Uint8Array |
Point | GEOGRAPHY::Point | GEOGRAPHY::Point | string | String | String | string |
List | NVARCHAR(MAX) | TEXT | List<{listType}> | List<{listType}> | [{listType}] | {listType}[] |
JsonObject | NVARCHAR(MAX) | JSONB | {jsonObjectType} | {jsonObjectType} | {jsonObjectType} | {jsonObjectType} |
Custom | NVARCHAR(MAX) | TEXT | {customFieldType} | {customFieldType} | {customFieldType} | {customFieldType} |
Row-Level Security
The row-level security code generated by the Scaffold tool relies on the definition of a security hierarchy, starting at the entity that represents the CallingUser
and going down to dependent entities. In order to turn on row-level security code generation, the root setting useRowLevelSecurity
must be set to true. You will also need to specify the systemCallingUserName
to bypass security code checks for System
calling users.
Every entity that needs security code generated for it will need to specify one of 3 settings:
isSystemEntity
- This entity can only be accessed by theSystem
calling user.isCallingUserIdentity
- This entity'sGUID
represents the identifier of theCallingUser
of the current request context. Most typically this is theUser
entity, and functions as the top-levelrowLevelSecurityParent
.rowLevelSecurityParent
- Name of the entity from which the current entity inherits its row-level security definition. This is what sets up the security hierarchy.
Row-level security checks will be generated directly within the stored procedures in order to ensure that any custom business logic that uses the generated data access code will benefit from the automated security checks. The types of checks performed depends on the type of the stored procedure:
INSERT
- If the entity that is being inserted contains a foreign key to the specifiedrowLevelSecurityParent
, a security check will be generated to make sure theCallingUser
has access to the parent entity record. If the entity being inserted contains foreign keys to other entities that have this entity specified as theirrowLevelSecurityParent
, a security check will also be generated to make sure theCallingUser
has access to those entity records as well.UPDATE
- A security check will be generated to make sure theCallingUser
has access to the entity record being updated. If the entity being updated contains foreign keys to other entities that have this entity specified as theirrowLevelSecurityParent
, and if the foreign key entity id is provided as a parameter, a security check will also be generated to make sure theCallingUser
has access to those entity records as well.DELETE
- A security check will be generated to make sure theCallingUser
has access to the entity record being deleted.SELECT
- A security check will be added to theWHERE
clause to make sure theCallingUser
has access to each of the returned entity records.
To add more SQL conditions for selecting or modifying an entity and its security children, use rowLevelSecuritySelectSqlCondition
and rowLevelSecurityModifySqlCondition
.
In order to make an entity that is protected by row-level security code allow public reads, disableRowLevelSecuritySelectSqlGeneration
can be set to true.
Extending Generated Code
When the root setting useBaseFolderStructure
is set to true, generated code will be placed in a Base
folder on every level (database, data access, logic, etc) and configured for extension and overrides. This allows the Scaffold tool to be re-runnable by cleaning the Base
folders on each run and re-generating all code. All custom extensions will be preserved since they are done in separate files and folders.
Placing generated code in separate folders also has the advantage of being able to easily distinguish custom code from the generated boilerplate code. For example, the following git command can be used to exclude generated files from the list of changed files, to more easily see the actual business logic that was modified:
git status ':!**/Base/*' ':!**/ContainerBootstrapBase.cs' ':!**/SampleData_Template.sql' ':!**/dbo/*' ':!*.dacpac'
Extending Database Code
When the starter project's DeployDatabase.ps1
script creates a new database, it runs SQL code in Base
folders first before executing the code outside of the Base
folders on each level. This means that extension .sql
files can be created on the same level as the Base
folder to modify the base SQL entities. In cases of table definition, the custom SQL file may add new columns, foreign keys, or constraints.
Extending stored procedures is a bit less convenient, since a stored procedure has to be specified in its entirety upon creation or modification. This is why each stored procedure is created using CREATE OR ALTER PROCEDURE
command to allow DeployDatabase.ps1
to overwrite existing stored procedures. For any stored procedure that needs to be extended, the base stored procedure .sql
file would be copied outside of the Procedures\Base
folder, and modifications applied directly to the copied file.
Remember that if any future modifications to scaffold.json
input file result in a modification the the base stored procedure, these updates will need to be propagated to the copied file as well. Because of this, it is best practice to put an -- Extended
comment next to each modification in the copied stored procedure file, to easily identify which parts came from the generated version.
Extending C# Code
Every generated C# class is marked as partial
in order to allow extending models and classes with additional properties and methods. Every generated method is also marked as virtual
in order to allow overrides. To support overriding methods from custom partial classes, the structure of the generated C# code is such that a partial class extends a base class that contains the actual implementation, which allows overrides of the base class's methods from custom partial extensions.
In cases when a layer requires custom implementation such that extending and/or overriding the base generated code will not suffice, the generation of code at the desired layer can be turned off per entity using various disableGeneration
settings.
Try It Out
The easiest way to try out the Scaffold tool is to start with the Plinth API Starter project, which provides the project structure as well as a sample scaffold.json
definition.
Clone the repository and follow the instructions in the API starter project to create a new project.
Then, run build-scaffold.bat
for the first time to generate code using the sample configuration provided in scaffold.json
file.
Make the desired changes to scaffold.json
and re-run build-scaffold.bat
to update generated code.
Support
While efforts are being made to maintain full support of every combination of the settings mentioned above, the reality is such that settings that are used in the more recent projects are the ones that get the most attention. For example, while PGSQL is a supported option for database code generation, row-level security and bulk insert stored procedures are only currently available in the MSSQL version of the database code, since there are no known current projects that use PGSQL.
If you find a bug or a gap in the settings that are needed for your project, please contact the Scaffold tool's administrators to report a bug, submit a feature request, or ask for assistance.
Alternatively, feel free to fork and modify the code to your liking, and submit a pull request for bug fixes or non-project-specific functionality.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
This package has no dependencies.
Version | Downloads | Last updated |
---|---|---|
1.0.25 | 216 | 11/7/2024 |
1.0.24 | 319 | 10/11/2024 |
1.0.22 | 263 | 9/18/2024 |
1.0.21 | 1,456 | 2/6/2024 |
1.0.20 | 193 | 2/4/2024 |
1.0.19 | 177 | 1/23/2024 |
1.0.18 | 180 | 1/17/2024 |
1.0.17 | 271 | 1/9/2024 |
1.0.16 | 212 | 1/2/2024 |
1.0.15 | 330 | 12/18/2023 |
1.0.14 | 208 | 12/18/2023 |
1.0.13 | 325 | 12/4/2023 |
1.0.12 | 323 | 7/30/2023 |
1.0.11 | 245 | 7/30/2023 |
1.0.10 | 268 | 5/12/2023 |
1.0.9 | 283 | 3/31/2023 |
1.0.8 | 335 | 3/17/2023 |
1.0.7 | 358 | 2/21/2023 |
1.0.6 | 331 | 2/11/2023 |
1.0.4 | 326 | 2/7/2023 |
1.0.3 | 310 | 2/6/2023 |
1.0.2 | 427 | 1/18/2023 |
1.0.1 | 374 | 1/16/2023 |
1.0.0 | 496 | 8/31/2022 |
1.0.0-b3.98d44555 | 128 | 8/31/2022 |
1.0.0-b2.84a70868 | 117 | 8/31/2022 |
initial release of Plinth.Scaffold