This guide provides comprehensive examples and patterns for AI assistants to help users with the EzDbCodeGen library.
// 1. Create a configuration
var configuration = new Configuration();
configuration.SetValue("Namespace", "MyApp");
configuration.SetValue("OutputPath", "./Generated");
// 2. Set up entity security (optional)
var entitySecurity = new Dictionary<string, EntitySecurity>
{
{ "Customer", new EntitySecurity { Secured = true } },
{ "Order", new EntitySecurity { Secured = false } }
};
configuration.SetValue("EntitySecurity", entitySecurity);
// 3. Create a database schema (using EzDbSchema or a mock)
var database = new MockDatabaseSchema().CreateMockDatabase();
var templateDataInput = new TemplateDataInput(database);
// 4. Create the code generator
var codeGenerator = new TestCodeGenerator(configuration);
// 5. Process templates
var modelTemplatePath = "Templates/EFCoreModel.hbs";
codeGenerator.ProcessModelTemplate(modelTemplatePath, templateDataInput, "./Generated");
var controllerTemplatePath = "Templates/EFCoreController.hbs";
codeGenerator.ProcessControllerTemplate(controllerTemplatePath, templateDataInput, "./Generated");
The database schema structure used by EzDbCodeGen is based on the EzDbSchema.Core library. Here's a detailed outline of the key components:
IDatabase
├── Name (string)
├── DefaultSchema (string)
├── Entities (IEntityDictionary<string, IEntity>)
│ ├── IEntity
│ │ ├── TableName (string)
│ │ ├── TableAlias (string)
│ │ ├── DatabaseSchema (string)
│ │ ├── EntityType (string) - Table, View, etc.
│ │ ├── Properties (IPropertyDictionary<string, IProperty>)
│ │ │ ├── IProperty
│ │ │ │ ├── PropertyName (string)
│ │ │ │ ├── ColumnName (string)
│ │ │ │ ├── DataType (string)
│ │ │ │ ├── IsNullable (bool)
│ │ │ │ ├── IsPrimaryKey (bool)
│ │ │ │ ├── IsIdentity (bool)
│ │ │ │ ├── IsRequired (bool)
│ │ │ │ ├── MaxLength (int)
│ │ │ │ ├── Precision (int)
│ │ │ │ ├── Scale (int)
│ │ │ │ ├── DefaultValue (string)
│ │ │ │ ├── IsReadOnly (bool)
│ │ │ │ ├── IsVisible (bool)
│ │ │ │ ├── IsEditable (bool)
│ │ │ │ ├── DisplayName (string)
│ │ │ │ ├── Description (string)
│ │ │ │ ├── ValidationRules (string)
│ │ │ │ ├── RequiresEncryption (bool)
│ │ │ │ ├── RequiresMasking (bool)
│ │ │ │ └── IsSensitive (bool)
│ │ ├── Relationships (IRelationshipReferenceList)
│ │ │ ├── IRelationship
│ │ │ │ ├── ConstraintName (string)
│ │ │ │ ├── FromTableName (string)
│ │ │ │ ├── FromColumnName (string)
│ │ │ │ ├── FromPropertyName (string)
│ │ │ │ ├── ToTableName (string)
│ │ │ │ ├── ToColumnName (string)
│ │ │ │ ├── ToPropertyName (string)
│ │ │ │ ├── MultiplicityType (RelationshipMultiplicityType)
│ │ │ │ │ ├── OneToOne
│ │ │ │ │ ├── OneToMany
│ │ │ │ │ ├── ManyToOne
│ │ │ │ │ ├── ManyToMany
│ │ │ │ │ ├── ZeroOrOneToOne
│ │ │ │ │ ├── ZeroOrOneToMany
│ │ │ │ │ └── ManyToZeroOrOne
│ │ │ │ ├── IsOptional (bool)
│ │ │ │ ├── CascadeDelete (bool)
│ │ │ │ ├── FromEntity (IEntity)
│ │ │ │ ├── ToEntity (IEntity)
│ │ │ │ ├── FromProperty (IProperty)
│ │ │ │ └── ToProperty (IProperty)
│ │ ├── RelationshipGroups (IRelationshipGroups)
│ │ ├── PrimaryKeys (IPrimaryKeyProperties)
│ │ ├── HasPrimaryKeys() (bool)
│ │ ├── HasForeignKeyConstraints (bool)
│ │ ├── RequiresAuthorization (bool)
│ │ ├── HasRowLevelSecurity (bool)
│ │ ├── IsAuditable() (bool)
│ │ └── IsVersioned (bool)
└── Relationships (List<IRelationship>)
The code generator uses Handlebars.Net to process templates. You can create templates for various code artifacts:
The IfCondEz
helper provides a powerful way to navigate the schema tree and evaluate complex conditions in your templates. It supports a rich expression language with proper order of operations, schema navigation, and various operators.
The IfCondEz
helper uses a dot notation with $
as the root context:
You can access nested properties using dot notation or array/dictionary syntax:
=
or==
- Equal to!=
or<>
- Not equal to>
- Greater than<
- Less than>=
- Greater than or equal to<=
- Less than or equal to
&&
- Logical AND||
- Logical OR!
ornot
- Logical NOT
contains
- Check if a string contains another stringstartsWith
- Check if a string starts with another stringendsWith
- Check if a string ends with another string
You can combine multiple conditions and use parentheses to control the order of evaluation:
The code generator automatically processes entity relationships to create navigation properties. Here's how different relationship types are handled:
// Example of processing one-to-many relationships
private IEnumerable<dynamic> GetOneToManyRelationships(IEntity entity)
{
var relationships = new List<dynamic>();
// Get relationships where this entity is the "one" side
var oneToManyRelationships = entity.Relationships
.Where(r => r.FromTableName == entity.TableName &&
(r.MultiplicityType == RelationshipMultiplicityType.OneToMany ||
r.MultiplicityType == RelationshipMultiplicityType.ZeroOrOneToMany));
foreach (var relationship in oneToManyRelationships)
{
var toEntity = relationship.ToEntity;
if (toEntity == null) continue;
// Create navigation property for the collection
var navigationProperty = toEntity.TableName.ToPlural().ToPascalCase();
relationships.Add(new
{
ConstraintName = relationship.ConstraintName,
FromTableName = relationship.FromTableName,
ToTableName = relationship.ToTableName,
NavigationProperty = navigationProperty,
RelatedEntity = toEntity.TableName.ToSingular().ToPascalCase(),
ForeignKeyProperty = relationship.ToColumnName.ToPascalCase(),
InverseNavigationProperty = entity.TableName.ToSingular().ToPascalCase(),
MultiplicityType = "OneToMany",
CascadeDelete = relationship.CascadeDelete
});
}
return relationships;
}
// Example of processing many-to-one relationships
private IEnumerable<dynamic> GetManyToOneRelationships(IEntity entity)
{
var relationships = new List<dynamic>();
// Get relationships where this entity is the "many" side
var manyToOneRelationships = entity.Relationships
.Where(r => r.ToTableName == entity.TableName &&
r.MultiplicityType == RelationshipMultiplicityType.ManyToOne);
foreach (var relationship in manyToOneRelationships)
{
var fromEntity = relationship.FromEntity;
if (fromEntity == null) continue;
// Create navigation property for the reference
var navigationProperty = fromEntity.TableName.ToSingular().ToPascalCase();
relationships.Add(new
{
ConstraintName = relationship.ConstraintName,
FromTableName = relationship.FromTableName,
ToTableName = relationship.ToTableName,
NavigationProperty = navigationProperty,
RelatedEntity = fromEntity.TableName.ToSingular().ToPascalCase(),
ForeignKeyProperty = relationship.FromColumnName.ToPascalCase(),
InverseNavigationProperty = entity.TableName.ToPlural().ToPascalCase(),
MultiplicityType = "ManyToOne",
CascadeDelete = relationship.CascadeDelete
});
}
return relationships;
}
// Example of processing one-to-one relationships
private IEnumerable<dynamic> GetOneToOneRelationships(IEntity entity)
{
var relationships = new List<dynamic>();
// Get one-to-one relationships
var oneToOneRelationships = entity.Relationships
.Where(r => r.MultiplicityType == RelationshipMultiplicityType.OneToOne ||
r.MultiplicityType == RelationshipMultiplicityType.ZeroOrOneToOne);
foreach (var relationship in oneToOneRelationships)
{
IEntity relatedEntity;
string navigationProperty;
string foreignKeyProperty;
if (relationship.FromTableName == entity.TableName)
{
relatedEntity = relationship.ToEntity;
navigationProperty = relatedEntity.TableName.ToSingular().ToPascalCase();
foreignKeyProperty = relationship.FromColumnName.ToPascalCase();
}
else
{
relatedEntity = relationship.FromEntity;
navigationProperty = relatedEntity.TableName.ToSingular().ToPascalCase();
foreignKeyProperty = relationship.ToColumnName.ToPascalCase();
}
if (relatedEntity == null) continue;
relationships.Add(new
{
ConstraintName = relationship.ConstraintName,
NavigationProperty = navigationProperty,
RelatedEntity = relatedEntity.TableName.ToSingular().ToPascalCase(),
ForeignKeyProperty = foreignKeyProperty,
InverseNavigationProperty = entity.TableName.ToSingular().ToPascalCase(),
MultiplicityType = "OneToOne",
CascadeDelete = relationship.CascadeDelete
});
}
return relationships;
}
EzDbCodeGen provides a rich set of Handlebars helpers to make template creation easier:
{{Debugger}}
- Adds a debug point (useful for development){{Comma}}
- Outputs a comma (useful in template loops){{ToJson value}}
- Converts a value to JSON format{{ContextAsJson}}
- Dumps the current context as JSON (great for debugging)
{{ToNetType}}
- Converts a database type to .NET type{{ToJsType}}
- Converts a database type to JavaScript type{{AsNullableType type isNullable}}
- Adds nullable marker (?) if needed
{{ToPascalCase}}
- Converts string to PascalCase{{ToCamelCase}}
- Converts string to camelCase{{ToSnakeCase}}
- Converts string to snake_case{{ToSingular}}
- Converts plural to singular{{ToPlural}}
- Converts singular to plural{{ToCodeFriendly}}
- Makes string code-friendly{{ExtractTableName}}
- Extracts table name from schema.table{{ExtractSchemaName}}
- Extracts schema name from schema.table{{AsFormattedName}}
- Formats name by removing common suffixes{{Prefix prefix value}}
- Adds prefix to string{{StringFormat value format1 format2...}}
- Applies multiple string formats
{{#IfPropertyExists propertyName}}...{{/IfPropertyExists}}
- Checks if property exists{{#IfFunctionExists functionName}}...{{/IfFunctionExists}}
- Checks if function exists{{#IfCond left op right}}...{{else}}...{{/IfCond}}
- Conditional logic with operators{{#Switch value}}{{#Case 'option'}}...{{/Case}}{{#Default}}...{{/Default}}{{/Switch}}
- Switch/case logic{{#IfCondEz "expression"}}...{{else}}...{{/IfCondEz}}
- Enhanced conditional expression evaluator with schema navigation and equation processing
{{tsType}}
- Converts to TypeScript type{{tsInterface}}
- Formats name as interface{{tsModel}}
- Formats name as model{{tsService}}
- Formats name as service{{tsComponent}}
- Formats name as component{{tsModule}}
- Formats name as module{{tsRouting}}
- Formats name as routing{{tsStore}}
- Formats name as store
{{POCOModelFKProperties}}
- Generates POCO model foreign key properties{{POCOModelFKManyToZeroToOne}}
- Generates POCO model many-to-zero-or-one relationships{{GetForeignKeyProperties}}
- Gets foreign key properties for an entity{{GetOneToOneReferences}}
- Gets one-to-one references{{GetForeignKeyCollectionsForEntity}}
- Gets foreign key collections
EzDbCodeGen works primarily through these core interfaces from EzDbSchema.Core:
The root interface representing your database schema:
public interface IDatabase
{
string Name { get; }
string DefaultSchema { get; }
IEntityDictionary<string, IEntity> Entities { get; }
}
Represents a database table or view:
public interface IEntity
{
string TableName { get; }
string TableAlias { get; }
string DatabaseSchema { get; }
string EntityType { get; } // Table, View, etc.
IPropertyDictionary<string, IProperty> Properties { get; }
IRelationshipReferenceList Relationships { get; }
bool HasPrimaryKeys();
bool HasForeignKeyConstraints { get; }
}
Represents a column in your database:
public interface IProperty
{
string PropertyName { get; }
string ColumnName { get; }
string DataType { get; }
bool IsNullable { get; }
bool IsPrimaryKey { get; }
bool IsIdentity { get; }
bool IsRequired { get; }
int MaxLength { get; }
string DefaultValue { get; }
}
Represents relationships between tables:
public interface IRelationship
{
string ConstraintName { get; }
string FromTableName { get; }
string FromColumnName { get; }
string ToTableName { get; }
string ToColumnName { get; }
RelationshipMultiplicityType MultiplicityType { get; }
bool IsOptional { get; }
IEntity FromEntity { get; }
IEntity ToEntity { get; }
}
Here are common patterns for working with these interfaces in your templates:
- Accessing Entity Properties:
- Working with Relationships:
- Handling Primary Keys:
- Schema-Aware Generation:
- Type Safety:
// Check entity type before processing
{{#if (eq EntityType "Table")}}
// Generate table-specific code
{{else}}
// Generate view-specific code
{{/if}}
- Null Handling:
- Relationship Navigation:
- Custom Attributes:
The code generator can skip entities marked as secured:
// Example of checking entity security
var entitySecurity = _configuration.EntitySecurity();
if (entitySecurity != null &&
entitySecurity.TryGetValue(entity.TableName, out var security) &&
security.Secured)
{
Console.WriteLine($"Skipping secured entity: {entity.TableName}");
continue;
}
When building templates from source files, follow these steps:
- Analyze the source file structure - Identify the patterns and components
- Extract variable parts - Replace with Handlebars expressions
- Add conditional logic - Use Handlebars conditionals for variations
- Handle loops - Use Handlebars each helpers for collections
- Test with sample data - Verify output matches expectations
Original class:
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<Order> Orders { get; set; }
}
Converted to template:
The EzDbCodeGen tool can be installed as a .NET global tool:
dotnet tool install --global EzDbCodeGen.Cli
Then use it to generate code:
ezdbcodegen -a MyApp -s dbo -t Templates/EFCoreModel.hbs -c "Server=localhost;Database=MyDB;Trusted_Connection=True;" -o ./Generated -v
Usage: ezdbcg [options]
Options:
-a|--app-name <n> Application name (default: "MyApp")
-s|--schema-name <n> Schema name (default: "MySchema")
-t|--template <PATH> Template file or directory path
-c|--connection-string <CS> Database connection string
-v|--verbose Enable verbose output
-o|--output <PATH> Output directory path
--save-settings Save current settings for future use
-?|-h|--help Show help information
For testing purposes, EzDbCodeGen supports an in-memory mode:
var command = new CommandMainTestable
{
UseInMemoryStorage = true,
AppName = "TestApp",
SchemaName = "TestSchema",
TemplateFileNameOrPath = "path/to/template.hbs",
ConnectionString = "Server=localhost;Database=TestDB;User Id=test;Password=test;"
};
// Set up mock database
command.SetMockDatabase(mockDatabase);
// Add template to in-memory storage
command.InMemoryFiles[command.TemplateFileNameOrPath] = "{{AppName}}";
// Execute
var result = command.TestOnExecute();
- The code generator creates debug output files with the prefix
DEBUG_
that can be useful for troubleshooting. - Template data is also saved as JSON files with the prefix
DEBUG_DATA_
for inspecting the data passed to templates. - Use the console output to see detailed information about the code generation process.
- Use the
{{ContextAsJson}}
helper to dump the current context for debugging.
- Missing navigation properties: Ensure that relationships are properly defined in the database schema.
- Incorrect casing: The code generator normalizes entity names to ensure proper casing.
- Template not found: Check that the template path is correct and the file exists.
- Entity security not working: Verify that the entity security configuration is properly set up.
- Null reference exceptions: Check for null values in templates using conditional helpers.
- Namespace issues: Be aware of the difference between EzDbSchema.Core.Extensions and EzDbSchema.Core.Extentions.
- Use normalized entity names for consistent casing
- Create separate templates for different types of code artifacts
- Use debug output for troubleshooting
- Test code generation with mock database schemas
- Use entity security to control which entities are included in code generation
- Leverage Handlebars helpers to simplify templates
- Use fluent API for complex entity relationships
- Create reusable partial templates for common patterns
- Implement proper null handling for collections and properties
- Use fully-qualified type names to avoid ambiguous references
This guide helps AI assistants understand and work with the EzDbCodeGen Core library's templating system.
Templates should follow these principles:
- Single Responsibility: Each template should generate one type of output
- Dependency Injection Ready: Use layouts to separate concerns
- Testable: Include test cases for template outputs
- SOLID Compliant: Follow SOLID principles in template organization
Operations (can be chained with comma or pipe):
-
Case Transformations:
camelCase
: "my_variable" → "myVariable"pascalCase
: "my_variable" → "MyVariable"snakeCase
: "myVariable" → "my_variable"kebabCase
: "myVariable" → "my-variable"uppercase
: "myVariable" → "MYVARIABLE"lowercase
: "MyVariable" → "myvariable"
-
Indentation:
indent2
: 2 spacesindent4
: 4 spaces (default)indent8
: 8 spaces
-
Tabbing:
tab1
: 1 tabtab2
: 2 tabstab4
: 4 tabs
Example:
Supported mappings:
// SQL to C#
"int" → "int" | "int?"
"varchar(50)" → "string"
"datetime" → "DateTime" | "DateTime?"
// SQL to TypeScript
"int" → "number"
"varchar" → "string"
"datetime" → "Date"
// SQL to Java
"int" → "Integer"
"varchar" → "String"
"datetime" → "LocalDateTime"
// SQL to Python
"int" → "int"
"varchar" → "str"
"datetime" → "datetime"
Example:
Documentation formats:
- XML (C#):
- JSDoc (TypeScript/JavaScript):
Template organization helper for structured code generation:
Features:
- Named regions for organization
- Partial template support
- Region ordering control
- Conditional region rendering
Language-specific formatting:
C#:
SQL:
- Schema Analysis:
// Analyze schema before generating templates
foreach (var table in schema.Tables)
{
// Check relationships
var hasOneToMany = table.Relationships.Any(r => r.Multiplicity == "OneToMany");
// Check primary keys
var hasPrimaryKey = table.Properties.Any(p => p.IsPrimaryKey);
}
- Template Pattern Selection:
- Entity classes: Use class templates with property generation
- Controllers: Use REST API templates with CRUD operations
- ViewModels: Use DTO templates with mapping
- Documentation: Use documentation templates with type info
- Code Style Compliance:
- Use
FormatEz
for consistent naming - Use
CodeFormatEz
for language-specific formatting - Use
DocEz
for standardized documentation - Use
LayoutEz
for organized output
- Testing Templates:
// Create test cases for templates
[Fact]
public void Template_GeneratesValidCode()
{
var template = @"
{{#each Tables}}
public class {{format 'pascalCase' Name}} {
{{#each Properties}}
{{doc this 'xml'}}
public {{convertType DataType 'csharp' IsNullable}} {{format 'pascalCase' Name}} { get; set; }
{{/each}}
}
{{/each}}
";
var result = generator.Generate(template, testSchema);
Assert.Contains("public class", result);
}
- Entity Class Template:
- API Controller Template:
- Repository Template:
-
Template Organization:
- Use layouts for structured output
- Separate concerns into regions
- Use partial templates for reusable components
-
Naming Conventions:
- Use consistent casing through FormatEz
- Follow language conventions
- Use descriptive region names
-
Documentation:
- Include XML/JSDoc comments
- Document relationships
- Add usage examples
-
Error Handling:
- Validate input schema
- Handle null values
- Include type checks
-
Testing:
- Create unit tests for templates
- Test edge cases
- Verify formatting
-
Performance:
- Use efficient helpers
- Minimize template complexity
- Cache compiled templates
Common issues and solutions:
-
Incorrect Type Conversion:
- Verify SQL type mapping
- Check nullable flag
- Use proper target language
-
Formatting Issues:
- Chain format operations correctly
- Check language-specific rules
- Verify template structure
-
Documentation Generation:
- Ensure proper metadata
- Check format specification
- Verify helper usage
The CLI tool provides robust connection testing capabilities through an interface-first design:
# Test connection with basic settings
ezdbcg --test-connection -c "Server=localhost;Database=MyDb;User Id=sa;Password=****"
# Test connection with custom timeout (in seconds)
ezdbcg --test-connection --connection-timeout 10 -c "Server=localhost;Database=MyDb;User Id=sa;Password=****"
# Test connection with SSL/TLS trust for development
ezdbcg --test-connection -c "Server=localhost;Database=MyDb;User Id=sa;Password=****;TrustServerCertificate=True"
The connection tester provides detailed feedback for various failure scenarios:
-
Connection String Format
- Empty or null connection string
- Missing required parameters (e.g., database name)
- Invalid connection string format
-
Authentication Issues
- Invalid credentials
- Insufficient permissions
- Missing or incorrect user/password
-
Network and Security
- Server unreachable
- SSL/TLS certificate validation failures
- Connection timeouts
- Pre-login handshake errors
-
Database Access
- Database does not exist
- Database not accessible
- Server configuration issues
The connection testing feature follows our interface-first approach:
// Core interface for connection testing
public interface IConnectionTester
{
Task<(ReturnCode Code, string Message)> TestConnectionAsync(string connectionString, int? timeoutSeconds = null);
}
// Usage in CLI
var tester = new MsSqlConnectionTester();
var (code, message) = await tester.TestConnectionAsync(connectionString, timeoutSeconds: 10);
This design allows for:
- Easy extension to other database providers
- Consistent error handling across implementations
- Clean separation of concerns
- Testable components
## Connection Testing
The CLI tool provides robust connection testing capabilities through an interface-first design:
```bash
# Test connection with basic settings
ezdbcg --test-connection -c "Server=localhost;Database=MyDb;User Id=sa;Password=****"
# Test connection with custom timeout (in seconds)
ezdbcg --test-connection --connection-timeout 10 -c "Server=localhost;Database=MyDb;User Id=sa;Password=****"
# Test connection with SSL/TLS trust for development
ezdbcg --test-connection -c "Server=localhost;Database=MyDb;User Id=sa;Password=****;TrustServerCertificate=True"
The connection tester provides detailed feedback for various failure scenarios:
-
Connection String Format
- Empty or null connection string
- Missing required parameters (e.g., database name)
- Invalid connection string format
-
Authentication Issues
- Invalid credentials
- Insufficient permissions
- Missing or incorrect user/password
-
Network and Security
- Server unreachable (with timeout details)
- SSL/TLS certificate validation failures
- Connection timeouts (customizable)
- Pre-login handshake errors
-
Database Access
- Database does not exist
- Database not accessible
- Server configuration issues
The connection testing feature follows our interface-first approach:
// Core interface for connection testing
public interface IConnectionTester
{
Task<(ReturnCode Code, string Message)> TestConnectionAsync(
string connectionString,
int? timeoutSeconds = null
);
}
// Example usage in code
var tester = new MsSqlConnectionTester();
var (code, message) = await tester.TestConnectionAsync(
connectionString,
timeoutSeconds: 10 // Optional timeout
);
This design allows for:
- Easy extension to other database providers
- Consistent error handling across implementations
- Clean separation of concerns
- Testable components
- Customizable timeouts
-
Connection String Security
// Use connection builder for safe string manipulation var builder = new SqlConnectionStringBuilder(connectionString) { TrustServerCertificate = true, ConnectTimeout = 30 };
-
Error Handling
try { var result = await tester.TestConnectionAsync(connectionString); // Handle result based on ReturnCode } catch (Exception ex) { // Handle unexpected errors }
-
Timeout Configuration
- Default timeout: 30 seconds
- Configurable via CLI:
--connection-timeout
- Overridable in connection string
- Respects existing timeout settings
- Handling Custom Attributes:
// Template pattern for accessing custom attributes safely
{{#each Properties}}
{{#if CustomAttributes}}
/// <summary>
/// {{lookup CustomAttributes "Description"}}
/// </summary>
{{#if (lookup CustomAttributes "Deprecated")}}
[Obsolete("{{lookup CustomAttributes "Deprecated"}}")]
{{/if}}
public {{convertType DataType "csharp" IsNullable}} {{format "pascalCase" Name}} { get; set; }
{{/if}}
{{/each}}
- Property Access Extensions:
- JSON Serialization Conflicts:
When dealing with namespace conflicts:
Template patterns for handling different schema versions:
-
Version Handling:
// Check schema version in template var schemaVersion = schema.Version ?? "8.4.0"; var useNewFeatures = Version.Parse(schemaVersion) >= Version.Parse("8.4.1");
-
Property Type Safety:
// Safe property type conversion public static string GetSafeTypeName(IProperty property) { if (string.IsNullOrEmpty(property?.DataType)) return "object"; return property.DataType.ToLowerInvariant() switch { "nvarchar" or "varchar" or "char" => "string", "int" or "bigint" => "int", "bit" => "bool", "datetime" or "datetime2" => "DateTime", _ => "object" }; }
-
Relationship Handling:
Common error patterns and their solutions:
- Missing References:
// Add package reference check in template
{{#layout}}
{{#region "package_check"}}
#if !EZDBSCHEMA_CORE_REFERENCE
#error Please add a reference to EzDbSchema.Core package
#endif
{{/region}}
{{/layout}}
- Type Resolution:
// Safe type resolution helper
public static string ResolveTypeName(string sqlType, bool isNullable)
{
var baseType = sqlType.Split('(')[0].ToLowerInvariant();
var csharpType = baseType switch
{
"nvarchar" or "varchar" or "char" => "string",
"int" => "int",
"bigint" => "long",
"bit" => "bool",
"decimal" or "money" => "decimal",
"datetime" or "datetime2" => "DateTime",
"uniqueidentifier" => "Guid",
_ => "object"
};
return csharpType == "string" ? csharpType : isNullable ? $"{csharpType}?" : csharpType;
}
- Null Checking:
- Handling Custom Attributes:
// Template pattern for accessing custom attributes safely
{{#each Properties}}
{{#if CustomAttributes}}
/// <summary>
/// {{lookup CustomAttributes "Description"}}
/// </summary>
{{#if (lookup CustomAttributes "Deprecated")}}
[Obsolete("{{lookup CustomAttributes "Deprecated"}}")]
{{/if}}
public {{convertType DataType "csharp" IsNullable}} {{format "pascalCase" Name}} { get; set; }
{{/if}}
{{/each}}
- Property Access Extensions:
- JSON Serialization Conflicts:
When dealing with namespace conflicts:
Template patterns for handling different schema versions:
-
Version Handling:
// Check schema version in template var schemaVersion = schema.Version ?? "8.4.0"; var useNewFeatures = Version.Parse(schemaVersion) >= Version.Parse("8.4.1");
-
Property Type Safety:
// Safe property type conversion public static string GetSafeTypeName(IProperty property) { if (string.IsNullOrEmpty(property?.DataType)) return "object"; return property.DataType.ToLowerInvariant() switch { "nvarchar" or "varchar" or "char" => "string", "int" or "bigint" => "int", "bit" => "bool", "datetime" or "datetime2" => "DateTime", _ => "object" }; }
-
Relationship Handling:
Common error patterns and their solutions:
- Missing References:
// Add package reference check in template
{{#layout}}
{{#region "package_check"}}
#if !EZDBSCHEMA_CORE_REFERENCE
#error Please add a reference to EzDbSchema.Core package
#endif
{{/region}}
{{/layout}}
- Type Resolution:
// Safe type resolution helper
public static string ResolveTypeName(string sqlType, bool isNullable)
{
var baseType = sqlType.Split('(')[0].ToLowerInvariant();
var csharpType = baseType switch
{
"nvarchar" or "varchar" or "char" => "string",
"int" => "int",
"bigint" => "long",
"bit" => "bool",
"decimal" or "money" => "decimal",
"datetime" or "datetime2" => "DateTime",
"uniqueidentifier" => "Guid",
_ => "object"
};
return csharpType == "string" ? csharpType : isNullable ? $"{csharpType}?" : csharpType;
}
- Null Checking: