Created
July 24, 2017 17:05
-
-
Save BryanWilhite/cc0c9b967059708832791bf17924ac6f to your computer and use it in GitHub Desktop.
Text Templating for EF Code-First over Oracle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Songhay.DataAccess.Oracle.Models; | |
using System.Collections.Generic; | |
namespace Songhay.DataAccess.Oracle.TextTemplating | |
{ | |
public partial class OracleEntityGenerator | |
{ | |
public OracleEntityGenerator(IEnumerable<OracleTableMetadata> metadata) | |
{ | |
this.TableOrViewMetadata = metadata; | |
} | |
public IEnumerable<OracleTableMetadata> TableOrViewMetadata { get; private set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #> | |
<#@ template debug="false" hostspecific="false" language="C#" #> | |
<#@ assembly name="Songhay.DataAccess.Oracle" #> | |
<#@ assembly name="System.Core" #> | |
<#@ import namespace="Songhay.DataAccess.Oracle.Extensions" #> | |
<#@ import namespace="System.Linq" #> | |
<#@ output extension=".cs" #> | |
<# | |
var className = this.TableOrViewMetadata.First().TableName.ToCamelCaseFromUnderscores(); | |
#> | |
using System; | |
using System.ComponentModel.DataAnnotations; | |
public class <#= className #> | |
{ | |
<# foreach (var p in this.TableOrViewMetadata) { #> | |
<#= p.ToDataAnnotationsOrEmpty() #>public <#= p.ToDotNetTypeName() #> <#= p.ColumnName.ToCamelCaseFromUnderscores() #> { get; set; } | |
<# } #> | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Songhay.DataAccess.Oracle.Models; | |
using System.Collections.Generic; | |
namespace Songhay.DataAccess.Oracle.TextTemplating | |
{ | |
public partial class OracleEntityMappingGenerator | |
{ | |
public OracleEntityMappingGenerator(IEnumerable<OracleTableMetadata> metadata) | |
{ | |
this.TableOrViewMetadata = metadata; | |
} | |
public IEnumerable<OracleTableMetadata> TableOrViewMetadata { get; private set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#@ CleanupBehavior processor="T4VSHost" CleanupAfterProcessingtemplate="true" #> | |
<#@ template debug="false" hostspecific="false" language="C#" #> | |
<#@ assembly name="Songhay.DataAccess.Oracle" #> | |
<#@ assembly name="System.Core" #> | |
<#@ import namespace="Songhay.DataAccess.Oracle.Extensions" #> | |
<#@ import namespace="System.Linq" #> | |
<#@ output extension=".cs" #> | |
<# | |
var tableOrViewName = this.TableOrViewMetadata.First().TableName; | |
var classNameForEntity = tableOrViewName.ToCamelCaseFromUnderscores(); | |
var className = $"{classNameForEntity}Map"; | |
#> | |
using System.Data.Entity.ModelConfiguration; | |
public class <#= className #> : EntityTypeConfiguration<<#= classNameForEntity #>> | |
{ | |
public <#= className #>() | |
{ | |
this.ToTable("<#= tableOrViewName #>"); | |
//TODO: set Key: this.HasKey(???); | |
<# foreach (var p in this.TableOrViewMetadata) { #> | |
this.Property(m => m.<#= p.ColumnName.ToCamelCaseFromUnderscores() #>).HasColumnName("<#= p.ColumnName #>")<# if((p.ToDotNetTypeName() == "string") && (p.DataLength > 0)) { #>.HasMaxLength(<#= p.DataLength #>).IsUnicode(false)<# } #>; | |
<# } #> | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Songhay.DataAccess.Oracle.Models | |
{ | |
/// <summary> | |
/// Represents output from <c>SYS.ALL_TAB_COLUMNS</c>. | |
/// </summary> | |
public partial class OracleTableMetadata | |
{ | |
/// <summary> | |
/// The Oracle <c>SYS.ALL_TAB_COLUMNS</c> parameterized SQL. | |
/// </summary> | |
/// <remarks> | |
/// Note that <c>TABLE_NAME</c> in the SQL below can specify a View name as well. | |
/// </remarks> | |
public const string OracleSysAllTabColumnsSql = @" | |
select | |
COLUMN_ID | |
, COLUMN_NAME | |
, NULLABLE | |
, DATA_TYPE | |
, DATA_PRECISION | |
, DATA_LENGTH | |
, DATA_SCALE | |
, DATA_DEFAULT | |
, TABLE_NAME | |
from | |
SYS.ALL_TAB_COLUMNS | |
where | |
TABLE_NAME = :tableOrViewName | |
"; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.ComponentModel.DataAnnotations; | |
using System.Text; | |
namespace Songhay.DataAccess.Oracle.Models | |
{ | |
/// <summary> | |
/// Represents output from <c>SYS.ALL_TAB_COLUMNS</c>. | |
/// </summary> | |
public partial class OracleTableMetadata | |
{ | |
/// <summary> | |
/// Gets or sets the column identifier. | |
/// </summary> | |
/// <value> | |
/// The column identifier. | |
/// </value> | |
public int? ColumnId { get; set; } | |
/// <summary> | |
/// Gets or sets the name of the column. | |
/// </summary> | |
/// <value> | |
/// The name of the column. | |
/// </value> | |
public string ColumnName { get; set; } | |
/// <summary> | |
/// Gets or sets a value indicating whether this instance is nullable. | |
/// </summary> | |
/// <value> | |
/// <c>true</c> if this instance is nullable; otherwise, <c>false</c>. | |
/// </value> | |
public bool? IsNullable { get; set; } | |
/// <summary> | |
/// Gets or sets the type of the data. | |
/// </summary> | |
/// <value> | |
/// The type of the data. | |
/// </value> | |
public string DataType { get; set; } | |
/// <summary> | |
/// Gets or sets the data precision. | |
/// </summary> | |
/// <value> | |
/// The data precision. | |
/// </value> | |
public int? DataPrecision { get; set; } | |
/// <summary> | |
/// Gets or sets the length of the data. | |
/// </summary> | |
/// <value> | |
/// The length of the data. | |
/// </value> | |
[Required] | |
public int DataLength { get; set; } | |
/// <summary> | |
/// Gets or sets the data scale. | |
/// </summary> | |
/// <value> | |
/// The data scale. | |
/// </value> | |
public int? DataScale { get; set; } | |
/// <summary> | |
/// Gets or sets the data default. | |
/// </summary> | |
/// <value> | |
/// The data default. | |
/// </value> | |
public string DataDefault { get; set; } | |
/// <summary> | |
/// Gets or sets the name of the table. | |
/// </summary> | |
/// <value> | |
/// The name of the table. | |
/// </value> | |
[Required] | |
public string TableName { get; set; } | |
/// <summary> | |
/// The string representation of this instance. | |
/// </summary> | |
public override string ToString() | |
{ | |
var sb = new StringBuilder(); | |
if (!string.IsNullOrEmpty(this.TableName)) sb.AppendFormat("TableName: {0}\n", this.TableName); | |
if (this.ColumnId != null) sb.AppendFormat("ColumnId: {0}\n", this.ColumnId); | |
if (!string.IsNullOrEmpty(this.ColumnName)) sb.AppendFormat("ColumnName: {0}\n", this.ColumnName); | |
if (this.IsNullable != null) sb.AppendFormat("IsNullable: {0}\n", this.IsNullable); | |
return (sb.Length > 0) ? sb.ToString() : base.ToString(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Songhay.DataAccess.Oracle.Models; | |
using System; | |
namespace Songhay.DataAccess.Oracle.Extensions | |
{ | |
/// <summary> | |
/// Extensions of <see cref="OracleTableMetadata"/> | |
/// </summary> | |
/// <remarks> | |
/// For research details, see “Oracle Data Types” | |
/// [https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm] | |
/// </remarks> | |
public static class OracleTableMetadataExtensions | |
{ | |
/// <summary> | |
/// Converts the <see cref="OracleTableMetadata"/> into a data annotations or <see cref="string.Empty"/>. | |
/// </summary> | |
/// <param name="metadata">The metadata.</param> | |
public static string ToDataAnnotationsOrEmpty(this OracleTableMetadata metadata) | |
{ | |
var annotations = string.Empty; | |
if (metadata == null) return annotations; | |
if (string.IsNullOrEmpty(metadata.DataType)) return annotations; | |
var dbTypeName = metadata.DataType.ToLowerInvariant(); | |
var isNullable = metadata.IsNullable.HasValue && metadata.IsNullable.GetValueOrDefault(); | |
var columnName = metadata.ColumnName.ToCamelCaseFromUnderscores(); | |
var newLinePlus4 = "\n "; | |
var maxLengthTemplate = "[MaxLength({0}, ErrorMessage = \"{1} cannot exceed {0} characters.\")]"; | |
var minLengthTemplate = "[MinLength({0}, ErrorMessage = \"{1} cannot have less than {0} characters.\")]"; | |
if (dbTypeName.Contains("varchar")) | |
{ | |
annotations = isNullable ? | |
string.Format(string.Concat(maxLengthTemplate, newLinePlus4), metadata.DataLength, columnName) | |
: | |
string.Format(string.Concat("[Required]", newLinePlus4, maxLengthTemplate, newLinePlus4), metadata.DataLength, columnName); | |
} | |
else if (dbTypeName.Contains("char")) | |
{ | |
annotations = isNullable ? | |
string.Format(string.Concat(maxLengthTemplate, newLinePlus4, minLengthTemplate, newLinePlus4), metadata.DataLength, columnName) | |
: | |
string.Format(string.Concat("[Required]", newLinePlus4, maxLengthTemplate, newLinePlus4, minLengthTemplate, newLinePlus4), metadata.DataLength, columnName); | |
} | |
return annotations; | |
} | |
/// <summary> | |
/// Converts the <see cref="OracleTableMetadata"/> into a .NET type name. | |
/// </summary> | |
/// <param name="metadata">The metadata.</param> | |
/// <remarks> | |
/// Reference: “Oracle to .NET type mapping” [https://www.devart.com/dotconnect/oracle/docs/DataTypeMapping.html] | |
/// </remarks> | |
public static string ToDotNetTypeName(this OracleTableMetadata metadata) | |
{ | |
if (metadata == null) return null; | |
if (string.IsNullOrEmpty(metadata.DataType)) return "object"; | |
var typeName = "string"; | |
switch (metadata.DataType.ToLowerInvariant()) | |
{ | |
case "date": | |
typeName = string.Concat(nameof(DateTime), metadata.IsNullable.GetValueOrDefault() ? "?" : string.Empty); | |
break; | |
case "number": | |
if (metadata.DataScale.GetValueOrDefault().Equals(0) || (metadata.DataScale == null)) | |
{ | |
typeName = (metadata.DataLength > 22) ? "long" : "int"; | |
} | |
else | |
{ | |
typeName = (metadata.DataPrecision.GetValueOrDefault() > 16) ? "double" : "decimal"; | |
} | |
typeName = string.Concat(typeName, metadata.IsNullable.GetValueOrDefault() ? "?" : string.Empty); | |
break; | |
} | |
return typeName; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment