⚠️feat: 正式删除mvc项目

This commit is contained in:
yubaolee 2025-06-07 23:55:12 +08:00
parent 7977e382d6
commit a6bd2c946b
20 changed files with 3 additions and 3187 deletions

View File

@ -1,204 +0,0 @@
<%--
Author: yubaolee
Description: 用于生成OpenAuth.WebApi接口相关代码包括controller/app/实体/dbcontext
--%>
<%@ Template Language="C#" TargetLanguage="Text" Debug="True" OutputType="Normal" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Assembly Name="CodeSmith.CustomProperties" %>
<%@ Assembly Name="Mono.Cecil" Path="..\Common" %>
<%@ Assembly Name="ICSharpCode.NRefactory" Path="..\Common" %>
<%@ Assembly Name="ICSharpCode.NRefactory.CSharp" Path="..\Common" %>
<%@ Assembly Src="Internal\Model.cs" %>
<%@ Assembly Src="Internal\Extensions.cs" %>
<%@ Assembly Src="Internal\Generator.cs" %>
<%@ Assembly Src="Internal\Parser.cs" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="SchemaMapper" %>
<%@ Property Name="WholeDb"
Type="System.Boolean"
Category="1.Database"
Default="true"
Description="是否直接生成选定数据库中的所有表" %>
<%@ Property Name="HeaderModel"
Type="System.Boolean"
Category="1.Database"
Default="true"
Description="是否为启用头表模式,即类似‘入库订单’界面" %>
<%@ Property Name="SourceDatabase"
Type="SchemaExplorer.DatabaseSchema"
Category="1.Database"
Description="The source database." %>
<%@ Property Name="SourceTables"
Type="SchemaExplorer.TableSchemaCollection"
Category="1.Database" Description="可以选择一个或多个表使用Ctrl键" %>
<%@ Property Name="directory"
Type="System.String"
Default=".\"
Optional="True"
Description="代码生成路径"
Editor="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>
<%@ Property Name="ContextNamespace"
Type="System.String"
Category="2.Class"
Default="OpenAuth.Repository"
OnChanged="OnContextNamespaceChanged"
Description="DbContext默认命名空间尽量不要更改"%>
<%@ Property Name="EntityNamespace"
Type="System.String"
Default="OpenAuth.Repository.Domain"
Category="2.Class"
Description="实体默认命名空间,尽量不要更改"%>
<%@ Register Name="EntityGeneratedClass"
Template="Internal\Entity.Generated.cst"
MergeProperties="False" %>
<%@ Register Name="ContextGeneratedClass"
Template="Internal\Context.Generated.cst"
MergeProperties="True" %>
<%@ Register Name="ApplicationGenerateClass"
Template="ApiGenerate\Application.cst"
MergeProperties="False" %>
<%@ Register Name="RequestGenerateClass"
Template="ApiGenerate\Request.cst"
MergeProperties="False" %>
<%@ Register Name="ModifyReqGenerateClass"
Template="ApiGenerate\ModifyReq.cst"
MergeProperties="False" %>
开始创建OpenAuth.Core WebApi相关代码 ...
<% Generate(); %>
<script runat="template">
private TableSchemaCollection tables;
public void Generate()
{
Stopwatch watch = Stopwatch.StartNew();
string outputDirectory = Path.GetFullPath(directory);
if(WholeDb){
tables = SourceDatabase.Tables;
}
else{
tables = SourceTables;
}
CreateEntityClasses();
CreateApplicationClass();
CreateReqClass();
CreateContextClass();
watch.Stop();
Response.WriteLine("Generate Time: " + watch.ElapsedMilliseconds + " ms");
}
//创建实体类
public void CreateEntityClasses()
{
EntityGeneratedClass generatedClass = this.Create<EntityGeneratedClass>();
this.CopyPropertiesTo(generatedClass);
foreach(TableSchema table in tables)
{
string className = table.Name;
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.Repository\\Domain\\" + className + ".cs";
generatedClass.Table = table;
Response.WriteLine("已生成"+generatedFile);
generatedClass.RenderToFile(generatedFile, generatedFile, true);
}
}
//创建DbContext
public void CreateContextClass()
{
ContextGeneratedClass generatedClass = this.Create<ContextGeneratedClass>();
this.CopyPropertiesTo(generatedClass);
string dbContextName;
if(WholeDb){
dbContextName = SourceDatabase.Name.ToSafeName();
}
else{
dbContextName = SourceTables.First().Database.Name.ToSafeName();
}
dbContextName = StringUtil.ToPascalCase(dbContextName);
string generatedFile = "OpenAuth.Repository\\" + dbContextName + "Context.cs";
Response.WriteLine("重要提示!!!!把下面内容添加到"+generatedFile+"对应的位置中,千万不要直接覆盖!!!");
Response.WriteLine(generatedClass.RenderToString());
}
//创建APP层,如UserManagerApp.cs
public void CreateApplicationClass()
{
ApplicationGenerateClass generatedClass = this.Create<ApplicationGenerateClass>();
this.CopyPropertiesTo(generatedClass);
foreach(TableSchema table in tables)
{
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.App\\"+ table.Name +"\\"+ table.Name + "App.cs";
generatedClass.Table = table;
//generatedClass.Entity = entity;
Response.WriteLine("已生成"+generatedFile);
generatedClass.RenderToFile(generatedFile, generatedFile, true);
}
}
//创建请求参数,如QueryUserListReq.cs
public void CreateReqClass()
{
RequestGenerateClass generatedClass = this.Create<RequestGenerateClass>();
this.CopyPropertiesTo(generatedClass);
foreach(TableSchema table in tables)
{
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.App\\"+ table.Name +"\\Request\\Query"+ table.Name + "ListReq.cs";
generatedClass.ModuleName = table.Name;
Response.WriteLine("已生成"+generatedFile);
generatedClass.RenderToFile(generatedFile, generatedFile, true);
}
//生成编辑修改的请求参数
ModifyReqGenerateClass modifyReqGenerateClass = this.Create<ModifyReqGenerateClass>();
this.CopyPropertiesTo(modifyReqGenerateClass);
foreach(TableSchema table in tables)
{
string generatedFile = Path.GetFullPath(directory) + "OpenAuth.App\\"+ table.Name +"\\Request\\AddOrUpdate"+ table.Name + "Req.cs";
modifyReqGenerateClass.Table = table;
Response.WriteLine("已生成"+generatedFile);
modifyReqGenerateClass.RenderToFile(generatedFile, generatedFile, true);
}
}
private void OnContextNamespaceChanged(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(ContextNamespace))
return;
if (string.IsNullOrEmpty(EntityNamespace))
EntityNamespace = ContextNamespace + ".Domain";
}
</script>

View File

@ -1,157 +0,0 @@
<%--
Name: Database Table Properties
Author: yubaolee
Description: Create a list of properties from a database table
--%>
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="True" Description="应用层" %>
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Property Name="Table"
Type="SchemaExplorer.TableSchema" %>
<%@ Property Name="HeaderModel"
Type="System.Boolean"
Category="1.Database"
Default="true"
Description="是否为启用头表模式,即类似‘入库订单’界面" %>
<%@ Assembly Src="../Web/Util.cs" %>
<%@ Import Namespace="Util" %>
using System;
using System.Linq;
using Infrastructure;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Interface;
namespace OpenAuth.App
{
public class <%=Table.Name%>App : BaseStringApp<<%=Table.Name%>, OpenAuthDBContext>
{
private RevelanceManagerApp _revelanceApp;
/// <summary>
/// 加载列表
/// </summary>
public TableData Load(Query<%=Table.Name%>ListReq request)
{
var loginContext = _auth.GetCurrentUser();
if (loginContext == null)
{
throw new CommonException("登录已过期", Define.INVALID_TOKEN);
}
//如果是WebAPI,请务必改为loginContext.GetTableColumns("<%=Table.Name%>");
var columnFields = loginContext.GetTableColumnsFromDb("<%=Table.Name%>");
if (columnFields == null || columnFields.Count == 0)
{
throw new Exception("请在代码生成界面配置Category表的字段属性");
}
var result = new TableData();
var objs = UnitWork.Find<<%=Table.Name%>>(null);
if (!string.IsNullOrEmpty(request.key))
{
objs = objs.Where(u => u.Id.Contains(request.key));
}
var propertyStr = string.Join(',', columnFields.Select(u =>u.ColumnName));
result.columnFields = columnFields;
result.data = objs.OrderBy(u => u.Id)
.Skip((request.page - 1) * request.limit)
.Take(request.limit).Select($"new ({propertyStr})");
result.count = objs.Count();
return result;
}
<%
if(Table.Name.Contains("Tbl") && (!Table.Name.Contains("Dtbl")) && this.HeaderModel){
var dtblName = Table.Name.Replace("Tbl","Dtbl"); //明细表的表名
%>
public void Add(AddOrUpdate<%=Table.Name%>Req req)
{
var obj = req.MapTo<<%=Table.Name%>>();
//todo:根据自己的业务场景,补充或调整字段
obj.CreateTime = DateTime.Now;
var user = _auth.GetCurrentUser().User;
obj.CreateUserId = user.Id;
obj.CreateUserName = user.Name;
UnitWork.Add(obj);
if (req.<%=dtblName%>Reqs != null && req.<%=dtblName%>Reqs.Any())
{
foreach (var detail in req.<%=dtblName%>Reqs)
{
detail.ForeignKeyId = obj.Id; //todo:调整自己的明细表外键
_<%=dtblName%>App.AddNoSave(detail);
}
}
UnitWork.Save();
}
public void Update(AddOrUpdate<%=Table.Name%>Req obj)
{
var user = _auth.GetCurrentUser().User;
if (obj.<%=dtblName%>Reqs != null && obj.<%=dtblName%>Reqs.Any())
{
//id为空的添加
foreach (var detail in obj.<%=dtblName%>Reqs.Where(u =>string.IsNullOrEmpty(u.Id)))
{
detail.ForeignKeyId = obj.Id; //todo:调整自己的明细表外键
_<%=dtblName%>App.AddNoSave(detail);
}
//id比数据库少的删除
var containids = obj.<%=dtblName%>Reqs.Select(u => u.Id)
.Where(u =>!string.IsNullOrEmpty(u)).ToList();
if (containids.Any())
{
UnitWork.Delete<<%=dtblName%>>(u =>(!containids.Contains(u.Id)) && u.ForeignKeyId == obj.Id); //todo:调整自己的明细表外键
}
//更新id相同的
foreach (var detail in obj.<%=dtblName%>Reqs.Where(u =>!string.IsNullOrEmpty(u.Id)))
{
_<%=dtblName%>App.Update(detail);
}
}
<%CreateUpdate();%>
UnitWork.Save();
}
<%
}else{ %>
public void Add(AddOrUpdate<%=Table.Name%>Req req)
{
var obj = req.MapTo<<%=Table.Name%>>();
//todo:根据自己的业务场景,补充或调整字段
//比如obj.CreateTime = DateTime.Now;
// var user = _auth.GetCurrentUser().User;
// obj.CreateUserId = user.Id;
// obj.CreateUserName = user.Name;
Repository.Add(obj);
}
public void Update(AddOrUpdate<%=Table.Name%>Req obj)
{
<%CreateUpdate();%>
}
<%
}
%>
public <%=Table.Name%>App(IUnitWork<OpenAuthDBContext> unitWork, IRepository<<%=Table.Name%>, OpenAuthDBContext> repository,
RevelanceManagerApp app, IAuth auth) : base(unitWork, repository,auth)
{
_revelanceApp = app;
}
}
}
<script runat="template">
/// <summary>
/// 创建更新字段
/// </summary>
public void CreateUpdate() {
var updatestr = Tools.CreateBlank(1) + "UnitWork.Update<" + Table.Name + ">(u => u.Id == obj.Id, u => new " + Table.Name + "\r\n";
updatestr +=Tools.CreateBlank(1) + "{\r\n";
var columnstr = "";
foreach (ColumnSchema p in Table.Columns) {
if (p.IsPrimaryKeyMember) continue ;
columnstr += Tools.CreateBlank(2)+ p.Name + " = obj." + p.Name + ", \r\n";
}
columnstr = columnstr.Substring(0, columnstr.Length - 4); //删除最后一个逗号
updatestr += columnstr;
updatestr += "\r\n" +Tools.CreateBlank(2) +"//todo:根据自己的业务场景,补充或调整字段";
updatestr += "\r\n" +Tools.CreateBlank(1) +"});";
Response.WriteLine(updatestr);
}
</script>

View File

@ -1,66 +0,0 @@
<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %>
<%@ Assembly Src="../Internal/Model.cs" %>
<%@ Assembly Src="../Internal/Extensions.cs" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>
<%@ Import Namespace="SchemaMapper" %>
<%@ Property Name="Table"
Type="SchemaExplorer.TableSchema" %>
<%@ Property Name="HeaderModel"
Type="System.Boolean"
Category="1.Database"
Default="true"
Description="是否为启用头表模式,即类似‘入库订单’界面" %>
<%@ Property Name="EntityNamespace"
Type="System.String" %>
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a CodeSmith Template.
//
// DO NOT MODIFY contents of this file. Changes to this
// file will be lost if the code is regenerated.
// Author:Yubao Li
// </autogenerated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using OpenAuth.Repository.Core;
namespace OpenAuth.App.Request
{
/// <summary>
/// <%= Table.Description %>
/// </summary>
[Table("<%= Table.Name%>")]
public partial class AddOrUpdate<%= Table.Name %>Req
{
<% foreach(ColumnSchema p in Table.Columns) {
%>
/// <summary>
/// <%=p.Description %>
/// </summary>
public <%= p.SystemType.ToNullableType(p.AllowDBNull == true) %> <%= p.Name%> { get; set; }
<% } %>
//todo:根据自己的业务场景添加需要的字段
<%
if(Table.Name.Contains("Tbl") && (!Table.Name.Contains("Dtbl")) && this.HeaderModel){
var dtblName = Table.Name.Replace("Tbl","Dtbl"); //明细表的表名
%>
public List<AddOrUpdate<%=dtblName%>Req> <%=dtblName%>Reqs { get; set; }
<% } %>
}
}

View File

@ -1,17 +0,0 @@
<%--
Name: Database Table Properties
Author: yubaolee
Description: Create a list of properties from a database table
--%>
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="False" Description="应用层" %>
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
namespace OpenAuth.App.Request
{
public class Query<%=ModuleName%>ListReq : PageReq
{
//todo:根据自己的业务场景添加需要的字段
}
}

View File

@ -1,81 +0,0 @@
<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %>
<%@ Assembly Src="../Internal/Model.cs" %>
<%@ Assembly Src="../Internal/Extensions.cs" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>
<%@ Import Namespace="SchemaMapper" %>
<%@ Property Name="WholeDb"
Type="System.Boolean"
Category="1.Database"
Default="true"
Description="是否为整个数据库" %>
<%@ Property Name="SourceDatabase"
Type="SchemaExplorer.DatabaseSchema"
Category="1.Database"
Description="The source database." %>
<%@ Property Name="SourceTables"
Type="SchemaExplorer.TableSchemaCollection"
Category="1.Database" Description="选择部分表" %>
<%@ Property Name="ContextNamespace" Type="System.String" %>
<%@ Property Name="EntityNamespace" Type="System.String" %>
using Microsoft.EntityFrameworkCore;
using <%= EntityNamespace %>;
namespace <%= ContextNamespace %>
{
<%
string dbContextName;
if(WholeDb){
dbContextName = SourceDatabase.Name.ToSafeName();
}
else{
dbContextName = SourceTables.First().Database.Name.ToSafeName();
}
dbContextName = StringUtil.ToPascalCase(dbContextName);
Response.WriteLine(" public partial class "+ dbContextName +"Context: DbContext");
%>
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//当主键为联合主键时,需要把这里的内容拷贝到对应的位置
<%
TableSchemaCollection tables;
if(WholeDb){
tables = SourceDatabase.Tables;
}
else{
tables = SourceTables;
}
foreach(TableSchema table in tables)
{
if(table.PrimaryKeys.Count <=1) continue;
var keys = string.Join(",", table.Columns.Where(u=>u.IsPrimaryKeyMember==true)
.Select(u =>"c."+u.Name));
Response.WriteLine(" modelBuilder.Entity<"+table.Name+">()");
Response.WriteLine(" .HasKey(c => new { "+keys+" });");
}
%>
}
<%
foreach(TableSchema table in tables)
{
Response.WriteLine(" public virtual DbSet<"+table.Name+"> "+StringUtil.ToPascalCase(StringUtil.ToPlural(table.Name))+" { get; set; }");
}
%>
}
}

View File

@ -1,75 +0,0 @@
<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %>
<%@ Assembly Src="../Internal/Model.cs" %>
<%@ Assembly Src="../Internal/Extensions.cs" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>
<%@ Import Namespace="SchemaMapper" %>
<%@ Property Name="Table"
Type="SchemaExplorer.TableSchema" %>
<%@ Property Name="EntityNamespace"
Type="System.String" %>
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a CodeSmith Template.
//
// DO NOT MODIFY contents of this file. Changes to this
// file will be lost if the code is regenerated.
// Author:Yubao Li
// </autogenerated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using OpenAuth.Repository.Core;
namespace <%= EntityNamespace %>
{
/// <summary>
/// <%= Table.Description %>
/// </summary>
[Table("<%= Table.Name%>")]
public partial class <%= Table.Name %> : StringEntity
{
public <%= Table.Name %>()
{
<% foreach(ColumnSchema p in Table.Columns) {
if(p.IsPrimaryKeyMember) continue;
string type = p.SystemType.ToNullableType(p.AllowDBNull == true);
if(type =="int" || type=="decimal")
Response.WriteLine(" this."+p.Name+"= 0;");
else if(type =="string")
Response.WriteLine(" this."+p.Name+"= string.Empty;");
else if(type.ToLower().Contains("datetime"))
Response.WriteLine(" this."+p.Name+"= DateTime.Now;");
} // foreach %>
}
<%
foreach(ColumnSchema p in Table.Columns) {
if(p.IsPrimaryKeyMember) continue;
%>
/// <summary>
/// <%=p.Description %>
/// </summary>
[Description("<%=p.Description%>")]
<%if(p.Name.LastIndexOf("Id") != -1){%>
[Browsable(false)]
<%}%>
<%if(p.DataType == DbType.Byte){%>
public bool <%= p.Name%> { get; set; }
<%}else{%>
public <%= p.SystemType.ToNullableType(p.AllowDBNull == true) %> <%= p.Name%> { get; set; }
<%}%>
<% } // foreach %>
}
}

View File

@ -1,187 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CodeSmith.Engine;
namespace SchemaMapper
{
public enum CodeLanguage
{
CSharp,
VisualBasic
}
public static class Extensions
{
private static readonly HashSet<string> _csharpKeywords;
private static readonly HashSet<string> _visualBasicKeywords;
private static readonly Dictionary<string, string> _csharpTypeAlias;
static Extensions()
{
_csharpKeywords = new HashSet<string>(StringComparer.Ordinal)
{
"as", "do", "if", "in", "is",
"for", "int", "new", "out", "ref", "try",
"base", "bool", "byte", "case", "char", "else", "enum", "goto", "lock", "long", "null", "this", "true", "uint", "void",
"break", "catch", "class", "const", "event", "false", "fixed", "float", "sbyte", "short", "throw", "ulong", "using", "while",
"double", "extern", "object", "params", "public", "return", "sealed", "sizeof", "static", "string", "struct", "switch", "typeof", "unsafe", "ushort",
"checked", "decimal", "default", "finally", "foreach", "private", "virtual",
"abstract", "continue", "delegate", "explicit", "implicit", "internal", "operator", "override", "readonly", "volatile",
"__arglist", "__makeref", "__reftype", "interface", "namespace", "protected", "unchecked",
"__refvalue", "stackalloc"
};
_visualBasicKeywords = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"as", "do", "if", "in", "is", "me", "of", "on", "or", "to",
"and", "dim", "end", "for", "get", "let", "lib", "mod", "new", "not", "rem", "set", "sub", "try", "xor",
"ansi", "auto", "byte", "call", "case", "cdbl", "cdec", "char", "cint", "clng", "cobj", "csng", "cstr", "date", "each", "else",
"enum", "exit", "goto", "like", "long", "loop", "next", "step", "stop", "then", "true", "wend", "when", "with",
"alias", "byref", "byval", "catch", "cbool", "cbyte", "cchar", "cdate", "class", "const", "ctype", "cuint", "culng", "endif", "erase", "error",
"event", "false", "gosub", "isnot", "redim", "sbyte", "short", "throw", "ulong", "until", "using", "while",
"csbyte", "cshort", "double", "elseif", "friend", "global", "module", "mybase", "object", "option", "orelse", "public", "resume", "return", "select", "shared",
"single", "static", "string", "typeof", "ushort",
"andalso", "boolean", "cushort", "decimal", "declare", "default", "finally", "gettype", "handles", "imports", "integer", "myclass", "nothing", "partial", "private", "shadows",
"trycast", "unicode", "variant",
"assembly", "continue", "delegate", "function", "inherits", "operator", "optional", "preserve", "property", "readonly", "synclock", "uinteger", "widening",
"addressof", "interface", "namespace", "narrowing", "overloads", "overrides", "protected", "structure", "writeonly",
"addhandler", "directcast", "implements", "paramarray", "raiseevent", "withevents",
"mustinherit", "overridable",
"mustoverride",
"removehandler",
"class_finalize", "notinheritable", "notoverridable",
"class_initialize"
};
_csharpTypeAlias = new Dictionary<string, string>(16)
{
{"System.Int16", "short"},
{"System.Int32", "int"},
{"System.Int64", "long"},
{"System.String", "string"},
{"System.Object", "object"},
{"System.Boolean", "bool"},
{"System.Void", "void"},
{"System.Char", "char"},
{"System.Byte", "byte"},
{"System.UInt16", "ushort"},
{"System.UInt32", "uint"},
{"System.UInt64", "ulong"},
{"System.SByte", "sbyte"},
{"System.Single", "float"},
{"System.Double", "double"},
{"System.Decimal", "decimal"}
};
}
public static string ToCamelCase(this string name)
{
return StringUtil.ToCamelCase(name);
}
public static string ToPascalCase(this string name)
{
return StringUtil.ToPascalCase(name);
}
public static string ToFieldName(this string name)
{
return "_" + StringUtil.ToCamelCase(name);
}
public static string MakeUnique(this string name, Func<string, bool> exists)
{
string uniqueName = name;
int count = 1;
while (exists(uniqueName))
uniqueName = string.Concat(name, count++);
return uniqueName;
}
public static bool IsKeyword(this string text, CodeLanguage language = CodeLanguage.CSharp)
{
return language == CodeLanguage.VisualBasic
? _visualBasicKeywords.Contains(text)
: _csharpKeywords.Contains(text);
}
public static string ToSafeName(this string name, CodeLanguage language = CodeLanguage.CSharp)
{
if (!name.IsKeyword(language))
return name;
return language == CodeLanguage.VisualBasic
? string.Format("[{0}]", name)
: "@" + name;
}
public static string ToType(this Type type, CodeLanguage language = CodeLanguage.CSharp)
{
return ToType(type.FullName, language);
}
public static string ToType(this string type, CodeLanguage language = CodeLanguage.CSharp)
{
if (type == "System.Xml.XmlDocument")
type = "System.String";
string t;
if (language == CodeLanguage.CSharp && _csharpTypeAlias.TryGetValue(type, out t))
return t;
return type;
}
public static string ToNullableType(this Type type, bool isNullable = false, CodeLanguage language = CodeLanguage.CSharp)
{
return ToNullableType(type.FullName, isNullable, language);
}
public static string ToNullableType(this string type, bool isNullable = false, CodeLanguage language = CodeLanguage.CSharp)
{
bool isValueType = type.IsValueType();
type = type.ToType(language);
if (!isValueType || !isNullable)
return type;
return language == CodeLanguage.VisualBasic
? string.Format("Nullable(Of {0})", type)
: type + "?";
}
public static bool IsValueType(this string type)
{
if (!type.StartsWith("System."))
return false;
var t = Type.GetType(type, false);
return t != null && t.IsValueType;
}
public static string ToDelimitedString(this IEnumerable<string> values, string delimiter, string format = null)
{
var sb = new StringBuilder();
foreach (var i in values)
{
if (sb.Length > 0)
sb.Append(delimiter);
if (string.IsNullOrEmpty(format))
sb.Append(i);
else
sb.AppendFormat(format, i);
}
return sb.ToString();
}
}
}

View File

@ -1,837 +0,0 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using CodeSmith.Engine;
using SchemaExplorer;
namespace SchemaMapper
{
public enum TableNaming
{
Mixed = 0,
Plural = 1,
Singular = 2
}
public enum EntityNaming
{
Preserve = 0,
Plural = 1,
Singular = 2
}
public enum RelationshipNaming
{
None = 0,
Plural = 1,
ListSuffix = 2
}
public enum ContextNaming
{
Preserve = 0,
Plural = 1,
TableSuffix = 2
}
public class GeneratorSettings
{
public GeneratorSettings()
{
RelationshipNaming = RelationshipNaming.ListSuffix;
EntityNaming = EntityNaming.Singular;
TableNaming = TableNaming.Singular;
CleanExpressions = new List<string> { @"^\d+" };
IgnoreExpressions = new List<string>();
}
public TableNaming TableNaming { get; set; }
public EntityNaming EntityNaming { get; set; }
public RelationshipNaming RelationshipNaming { get; set; }
public ContextNaming ContextNaming { get; set; }
public List<string> IgnoreExpressions { get; set; }
public List<string> CleanExpressions { get; set; }
public bool InclusionMode { get; set; }
public bool IsIgnored(string name)
{
if (IgnoreExpressions.Count == 0)
return false;
bool isMatch = IgnoreExpressions.Any(regex => Regex.IsMatch(name, regex));
return InclusionMode ? !isMatch : isMatch;
}
public string CleanName(string name)
{
if (CleanExpressions.Count == 0)
return name;
foreach (var regex in CleanExpressions.Where(r => !string.IsNullOrEmpty(r)))
if (Regex.IsMatch(name, regex))
return Regex.Replace(name, regex, "");
return name;
}
public string RelationshipName(string name)
{
if (RelationshipNaming == RelationshipNaming.None)
return name;
if (RelationshipNaming == RelationshipNaming.ListSuffix)
return name + "List";
return StringUtil.ToPascalCase(StringUtil.ToPlural(name));
}
public string ContextName(string name)
{
if (ContextNaming == ContextNaming.Preserve)
return name;
if (ContextNaming == ContextNaming.TableSuffix)
return name + "Table";
return StringUtil.ToPascalCase(StringUtil.ToPlural(name));
}
public string EntityName(string name)
{
if (TableNaming != TableNaming.Plural && EntityNaming == EntityNaming.Plural)
name = StringUtil.ToPlural(name);
else if (TableNaming != TableNaming.Singular && EntityNaming == EntityNaming.Singular)
name = StringUtil.ToSingular(name);
return StringUtil.ToPascalCase(name);
}
}
public class SchemaItemProcessedEventArgs : EventArgs
{
public SchemaItemProcessedEventArgs(string name)
{
_name = name;
}
private readonly string _name;
public string Name
{
get { return _name; }
}
}
public class UniqueNamer
{
private readonly ConcurrentDictionary<string, HashSet<string>> _names;
public UniqueNamer()
{
_names = new ConcurrentDictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
Comparer = StringComparer.CurrentCulture;
// add existing
UniqueContextName("ChangeTracker");
UniqueContextName("Configuration");
UniqueContextName("Database");
UniqueContextName("InternalContext");
}
public IEqualityComparer<string> Comparer { get; set; }
public string UniqueName(string bucketName, string name)
{
var hashSet = _names.GetOrAdd(bucketName, k => new HashSet<string>(Comparer));
string result = name.MakeUnique(hashSet.Contains);
hashSet.Add(result);
return result;
}
public string UniqueClassName(string className)
{
const string globalClassName = "global::ClassName";
return UniqueName(globalClassName, className);
}
public string UniqueContextName(string name)
{
const string globalContextname = "global::ContextName";
return UniqueName(globalContextname, name);
}
public string UniqueRelationshipName(string name)
{
const string globalContextname = "global::RelationshipName";
return UniqueName(globalContextname, name);
}
}
public class Generator
{
private readonly UniqueNamer _namer;
public Generator()
{
_settings = new GeneratorSettings();
_namer = new UniqueNamer();
}
public event EventHandler<SchemaItemProcessedEventArgs> SchemaItemProcessed;
protected void OnSchemaItemProcessed(string name)
{
var handler = SchemaItemProcessed;
if (handler == null)
return;
handler(this, new SchemaItemProcessedEventArgs(name));
}
private readonly GeneratorSettings _settings;
public GeneratorSettings Settings
{
get { return _settings; }
}
//按表信息创建DbContext
public EntityContext Generate(TableSchema tableSchema)
{
// only DeepLoad when in ignore mode
tableSchema.DeepLoad = !Settings.InclusionMode;
var entityContext = new EntityContext();
entityContext.DatabaseName = tableSchema.Database.Name;
string dataContextName = StringUtil.ToPascalCase(tableSchema.Database.Name) + "Context";
dataContextName = _namer.UniqueClassName(dataContextName);
entityContext.ClassName = dataContextName;
GetEntity(entityContext, tableSchema);
return entityContext;
}
//按数据库连接信息创建DbContext
public EntityContext Generate(DatabaseSchema databaseSchema)
{
// only DeepLoad when in ignore mode
databaseSchema.DeepLoad = !Settings.InclusionMode;
var entityContext = new EntityContext();
entityContext.DatabaseName = databaseSchema.Name;
string dataContextName = StringUtil.ToPascalCase(databaseSchema.Name) + "Context";
dataContextName = _namer.UniqueClassName(dataContextName);
entityContext.ClassName = dataContextName;
foreach (TableSchema t in databaseSchema.Tables)
{
if (Settings.IsIgnored(t.FullName))
{
Debug.WriteLine("Skipping Table: " + t.FullName);
}
else if (IsManyToMany(t))
{
CreateManyToMany(entityContext, t);
}
else
{
Debug.WriteLine("Getting Table Schema: " + t.FullName);
GetEntity(entityContext, t);
}
OnSchemaItemProcessed(t.FullName);
}
return entityContext;
}
//根据DbContext和tableSchema获取实体
public Entity GetEntity(EntityContext entityContext, TableSchema tableSchema, bool processRelationships = true, bool processMethods = true)
{
string key = tableSchema.FullName;
Entity entity = entityContext.Entities.ByTable(key)
?? CreateEntity(entityContext, tableSchema);
if (!entity.Properties.IsProcessed)
CreateProperties(entity, tableSchema);
if (processRelationships && !entity.Relationships.IsProcessed)
CreateRelationships(entityContext, entity, tableSchema);
if (processMethods && !entity.Methods.IsProcessed)
CreateMethods(entity, tableSchema);
entity.IsProcessed = true;
return entity;
}
private Entity CreateEntity(EntityContext entityContext, TableSchema tableSchema)
{
var entity = new Entity
{
FullName = tableSchema.FullName,
TableName = tableSchema.Name,
TableSchema = tableSchema.Owner,
Description = tableSchema.Description
};
string className = ToClassName(tableSchema.Name);
className = _namer.UniqueClassName(className);
string mappingName = className + "Map";
mappingName = _namer.UniqueClassName(mappingName);
string contextName = Settings.ContextName(className);
contextName = ToPropertyName(entityContext.ClassName, contextName);
contextName = _namer.UniqueContextName(contextName);
entity.ClassName = className;
entity.ContextName = contextName;
entity.MappingName = mappingName;
entityContext.Entities.Add(entity);
return entity;
}
/// <summary>
/// 创建实体的属性
/// </summary>
private void CreateProperties(Entity entity, TableSchema tableSchema)
{
foreach (ColumnSchema columnSchema in tableSchema.Columns)
{
// skip unsupported type
if (columnSchema.NativeType.Equals("hierarchyid", StringComparison.OrdinalIgnoreCase)
|| columnSchema.NativeType.Equals("sql_variant", StringComparison.OrdinalIgnoreCase))
{
Debug.WriteLine(string.Format("Skipping column '{0}' because it has an unsupported db type '{1}'.",
columnSchema.Name, columnSchema.NativeType));
continue;
}
Property property = entity.Properties.ByColumn(columnSchema.Name);
if (property == null)
{
property = new Property { ColumnName = columnSchema.Name };
entity.Properties.Add(property);
}
string propertyName = ToPropertyName(entity.ClassName, columnSchema.Name);
propertyName = _namer.UniqueName(entity.ClassName, propertyName);
property.PropertyName = propertyName;
property.DataType = columnSchema.DataType;
property.SystemType = columnSchema.SystemType;
property.NativeType = columnSchema.NativeType;
property.Description = columnSchema.Description;
property.IsPrimaryKey = columnSchema.IsPrimaryKeyMember;
property.IsForeignKey = columnSchema.IsForeignKeyMember;
property.IsNullable = columnSchema.AllowDBNull;
property.IsIdentity = IsIdentity(columnSchema);
property.IsRowVersion = IsRowVersion(columnSchema);
property.IsAutoGenerated = IsDbGenerated(columnSchema);
if (columnSchema.IsUnique)
property.IsUnique = columnSchema.IsUnique;
if (property.SystemType == typeof(string)
|| property.SystemType == typeof(byte[]))
{
property.MaxLength = columnSchema.Size;
}
if (property.SystemType == typeof(float)
|| property.SystemType == typeof(double)
|| property.SystemType == typeof(decimal))
{
property.Precision = columnSchema.Precision;
property.Scale = columnSchema.Scale;
}
property.IsProcessed = true;
}
entity.Properties.IsProcessed = true;
}
private void CreateRelationships(EntityContext entityContext, Entity entity, TableSchema tableSchema)
{
foreach (TableKeySchema tableKey in tableSchema.ForeignKeys)
{
if (Settings.IsIgnored(tableKey.ForeignKeyTable.FullName)
|| Settings.IsIgnored(tableKey.PrimaryKeyTable.FullName))
{
Debug.WriteLine("Skipping relationship '{0}' because table '{1}' or '{2}' is ignored.",
tableKey.FullName, tableKey.ForeignKeyTable.FullName, tableKey.PrimaryKeyTable.FullName);
continue;
}
CreateRelationship(entityContext, entity, tableKey);
}
entity.Relationships.IsProcessed = true;
}
private void CreateRelationship(EntityContext entityContext, Entity foreignEntity, TableKeySchema tableKeySchema)
{
Entity primaryEntity = GetEntity(entityContext, tableKeySchema.PrimaryKeyTable, false, false);
string primaryName = primaryEntity.ClassName;
string foreignName = foreignEntity.ClassName;
string relationshipName = tableKeySchema.Name;
relationshipName = _namer.UniqueRelationshipName(relationshipName);
bool isCascadeDelete = IsCascadeDelete(tableKeySchema);
bool foreignMembersRequired;
bool primaryMembersRequired;
var foreignMembers = GetKeyMembers(foreignEntity, tableKeySchema.ForeignKeyMemberColumns, tableKeySchema.Name, out foreignMembersRequired);
var primaryMembers = GetKeyMembers(primaryEntity, tableKeySchema.PrimaryKeyMemberColumns, tableKeySchema.Name, out primaryMembersRequired);
Relationship foreignRelationship = foreignEntity.Relationships
.FirstOrDefault(r => r.RelationshipName == relationshipName && r.IsForeignKey);
if (foreignRelationship == null)
{
foreignRelationship = new Relationship { RelationshipName = relationshipName };
foreignEntity.Relationships.Add(foreignRelationship);
}
foreignRelationship.IsMapped = true;
foreignRelationship.IsForeignKey = true;
foreignRelationship.ThisCardinality = foreignMembersRequired ? Cardinality.One : Cardinality.ZeroOrOne;
foreignRelationship.ThisEntity = foreignName;
foreignRelationship.ThisProperties = new List<string>(foreignMembers);
foreignRelationship.OtherEntity = primaryName;
foreignRelationship.OtherProperties = new List<string>(primaryMembers);
foreignRelationship.CascadeDelete = isCascadeDelete;
string prefix = GetMemberPrefix(foreignRelationship, primaryName, foreignName);
string foreignPropertyName = ToPropertyName(foreignEntity.ClassName, prefix + primaryName);
foreignPropertyName = _namer.UniqueName(foreignEntity.ClassName, foreignPropertyName);
foreignRelationship.ThisPropertyName = foreignPropertyName;
// add reverse
Relationship primaryRelationship = primaryEntity.Relationships
.FirstOrDefault(r => r.RelationshipName == relationshipName && r.IsForeignKey == false);
if (primaryRelationship == null)
{
primaryRelationship = new Relationship { RelationshipName = relationshipName };
primaryEntity.Relationships.Add(primaryRelationship);
}
primaryRelationship.IsMapped = false;
primaryRelationship.IsForeignKey = false;
primaryRelationship.ThisEntity = primaryName;
primaryRelationship.ThisProperties = new List<string>(primaryMembers);
primaryRelationship.OtherEntity = foreignName;
primaryRelationship.OtherProperties = new List<string>(foreignMembers);
primaryRelationship.CascadeDelete = isCascadeDelete;
bool isOneToOne = IsOneToOne(tableKeySchema, foreignRelationship);
if (isOneToOne)
primaryRelationship.ThisCardinality = primaryMembersRequired ? Cardinality.One : Cardinality.ZeroOrOne;
else
primaryRelationship.ThisCardinality = Cardinality.Many;
string primaryPropertyName = prefix + foreignName;
if (!isOneToOne)
primaryPropertyName = Settings.RelationshipName(primaryPropertyName);
primaryPropertyName = ToPropertyName(primaryEntity.ClassName, primaryPropertyName);
primaryPropertyName = _namer.UniqueName(primaryEntity.ClassName, primaryPropertyName);
primaryRelationship.ThisPropertyName = primaryPropertyName;
foreignRelationship.OtherPropertyName = primaryRelationship.ThisPropertyName;
foreignRelationship.OtherCardinality = primaryRelationship.ThisCardinality;
primaryRelationship.OtherPropertyName = foreignRelationship.ThisPropertyName;
primaryRelationship.OtherCardinality = foreignRelationship.ThisCardinality;
foreignRelationship.IsProcessed = true;
primaryRelationship.IsProcessed = true;
}
private void CreateManyToMany(EntityContext entityContext, TableSchema joinTable)
{
if (joinTable.ForeignKeys.Count != 2)
return;
var joinTableName = joinTable.Name;
var joinSchemaName = joinTable.Owner;
// first fkey is always left, second fkey is right
var leftForeignKey = joinTable.ForeignKeys[0];
var leftTable = leftForeignKey.PrimaryKeyTable;
var joinLeftColumn = leftForeignKey.ForeignKeyMemberColumns.Select(c => c.Name).ToList();
var leftEntity = GetEntity(entityContext, leftTable, false, false);
var rightForeignKey = joinTable.ForeignKeys[1];
var rightTable = rightForeignKey.PrimaryKeyTable;
var joinRightColumn = rightForeignKey.ForeignKeyMemberColumns.Select(c => c.Name).ToList();
var rightEntity = GetEntity(entityContext, rightTable, false, false);
string leftPropertyName = Settings.RelationshipName(rightEntity.ClassName);
leftPropertyName = _namer.UniqueName(leftEntity.ClassName, leftPropertyName);
string rightPropertyName = Settings.RelationshipName(leftEntity.ClassName);
rightPropertyName = _namer.UniqueName(rightEntity.ClassName, rightPropertyName);
string relationshipName = string.Format("{0}|{1}",
leftForeignKey.Name,
rightForeignKey.Name);
relationshipName = _namer.UniqueRelationshipName(relationshipName);
var left = new Relationship { RelationshipName = relationshipName };
left.IsForeignKey = false;
left.IsMapped = true;
left.ThisCardinality = Cardinality.Many;
left.ThisEntity = leftEntity.ClassName;
left.ThisPropertyName = leftPropertyName;
left.OtherCardinality = Cardinality.Many;
left.OtherEntity = rightEntity.ClassName;
left.OtherPropertyName = rightPropertyName;
left.JoinTable = joinTableName;
left.JoinSchema = joinSchemaName;
left.JoinThisColumn = new List<string>(joinLeftColumn);
left.JoinOtherColumn = new List<string>(joinRightColumn);
leftEntity.Relationships.Add(left);
var right = new Relationship { RelationshipName = relationshipName };
right.IsForeignKey = false;
right.IsMapped = false;
right.ThisCardinality = Cardinality.Many;
right.ThisEntity = rightEntity.ClassName;
right.ThisPropertyName = rightPropertyName;
right.OtherCardinality = Cardinality.Many;
right.OtherEntity = leftEntity.ClassName;
right.OtherPropertyName = leftPropertyName;
right.JoinTable = joinTableName;
right.JoinSchema = joinSchemaName;
right.JoinThisColumn = new List<string>(joinRightColumn);
right.JoinOtherColumn = new List<string>(joinLeftColumn);
rightEntity.Relationships.Add(right);
}
private void CreateMethods(Entity entity, TableSchema tableSchema)
{
if (tableSchema.HasPrimaryKey)
{
var method = GetMethodFromColumns(entity, tableSchema.PrimaryKey.MemberColumns);
if (method != null)
{
method.IsKey = true;
method.SourceName = tableSchema.PrimaryKey.FullName;
if (!entity.Methods.Any(m => m.NameSuffix == method.NameSuffix))
entity.Methods.Add(method);
}
}
GetIndexMethods(entity, tableSchema);
GetForeignKeyMethods(entity, tableSchema);
entity.Methods.IsProcessed = true;
}
private static void GetForeignKeyMethods(Entity entity, TableSchema table)
{
var columns = new List<ColumnSchema>();
foreach (ColumnSchema column in table.ForeignKeyColumns)
{
columns.Add(column);
Method method = GetMethodFromColumns(entity, columns);
if (method != null && !entity.Methods.Any(m => m.NameSuffix == method.NameSuffix))
entity.Methods.Add(method);
columns.Clear();
}
}
private static void GetIndexMethods(Entity entity, TableSchema table)
{
foreach (IndexSchema index in table.Indexes)
{
Method method = GetMethodFromColumns(entity, index.MemberColumns);
if (method == null)
continue;
method.SourceName = index.FullName;
method.IsUnique = index.IsUnique;
method.IsIndex = true;
if (!entity.Methods.Any(m => m.NameSuffix == method.NameSuffix))
entity.Methods.Add(method);
}
}
private static Method GetMethodFromColumns(Entity entity, IEnumerable<ColumnSchema> columns)
{
var method = new Method();
string methodName = string.Empty;
foreach (var column in columns)
{
var property = entity.Properties.ByColumn(column.Name);
if (property == null)
continue;
method.Properties.Add(property);
methodName += property.PropertyName;
}
if (method.Properties.Count == 0)
return null;
method.NameSuffix = methodName;
return method;
}
private static List<string> GetKeyMembers(Entity entity, IEnumerable<MemberColumnSchema> members, string name, out bool isRequired)
{
var keyMembers = new List<string>();
isRequired = false;
foreach (var member in members)
{
var property = entity.Properties.ByColumn(member.Name);
if (property == null)
throw new InvalidOperationException(string.Format(
"Could not find column {0} for relationship {1}.",
member.Name,
name));
if (!isRequired)
isRequired = property.IsRequired;
keyMembers.Add(property.PropertyName);
}
return keyMembers;
}
private static string GetMemberPrefix(Relationship relationship, string primaryClass, string foreignClass)
{
string thisKey = relationship.ThisProperties.FirstOrDefault() ?? string.Empty;
string otherKey = relationship.OtherProperties.FirstOrDefault() ?? string.Empty;
bool isSameName = thisKey.Equals(otherKey, StringComparison.OrdinalIgnoreCase);
isSameName = (isSameName || thisKey.Equals(primaryClass + otherKey, StringComparison.OrdinalIgnoreCase));
string prefix = string.Empty;
if (isSameName)
return prefix;
prefix = thisKey.Replace(otherKey, "");
prefix = prefix.Replace(primaryClass, "");
prefix = prefix.Replace(foreignClass, "");
prefix = Regex.Replace(prefix, @"(_ID|_id|_Id|\.ID|\.id|\.Id|ID|Id)$", "");
prefix = Regex.Replace(prefix, @"^\d", "");
return prefix;
}
private static bool IsOneToOne(TableKeySchema tableKeySchema, Relationship foreignRelationship)
{
bool isFkeyPkey = tableKeySchema.ForeignKeyTable.HasPrimaryKey
&& tableKeySchema.ForeignKeyTable.PrimaryKey != null
&& tableKeySchema.ForeignKeyTable.PrimaryKey.MemberColumns.Count == 1
&& tableKeySchema.ForeignKeyTable.PrimaryKey.MemberColumns.Contains(
foreignRelationship.ThisProperties.FirstOrDefault());
if (isFkeyPkey)
return true;
// if f.key is unique
return tableKeySchema.ForeignKeyMemberColumns.All(column => column.IsUnique);
}
private static bool IsManyToMany(TableSchema tableSchema)
{
// 1) Table must have Two ForeignKeys.
// 2) All columns must be either...
// a) Member of a Foreign Key.
// b) DbGenerated
if (tableSchema.Columns.Count < 2)
return false;
if (tableSchema.ForeignKeyColumns.Count != 2)
return false;
// all columns are fkeys
if (tableSchema.Columns.Count == 2 &&
tableSchema.ForeignKeyColumns.Count == 2)
return true;
// check all non fkey columns to make sure db gen'd
return tableSchema.NonForeignKeyColumns.All(c =>
IsDbGenerated(c) || HasDefaultValue(c));
}
#region Name Helpers
private string ToClassName(string name)
{
name = Settings.EntityName(name);
string legalName = ToLegalName(name);
return legalName;
}
private string ToPropertyName(string className, string name)
{
string propertyName = ToLegalName(name);
if (className.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
propertyName += "Member";
return propertyName;
}
private string ToLegalName(string name)
{
string legalName = Settings.CleanName(name);
legalName = StringUtil.ToPascalCase(legalName);
return legalName;
}
#endregion
#region Column Flag Helpers
private static bool IsCascadeDelete(SchemaObjectBase column)
{
bool cascadeDelete = false;
string value;
try
{
if (column.ExtendedProperties.Contains(ExtendedPropertyNames.CascadeDelete))
{
value = column.ExtendedProperties[ExtendedPropertyNames.CascadeDelete].Value.ToString();
bool.TryParse(value, out cascadeDelete);
}
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
return cascadeDelete;
}
private static bool IsRowVersion(DataObjectBase column)
{
bool isTimeStamp = column.NativeType.Equals(
"timestamp", StringComparison.OrdinalIgnoreCase);
bool isRowVersion = column.NativeType.Equals(
"rowversion", StringComparison.OrdinalIgnoreCase);
return (isTimeStamp || isRowVersion);
}
private static bool IsDbGenerated(DataObjectBase column)
{
if (IsRowVersion(column))
return true;
if (IsIdentity(column))
return true;
bool isComputed = false;
string value;
try
{
if (column.ExtendedProperties.Contains(ExtendedPropertyNames.IsComputed))
{
value = column.ExtendedProperties[ExtendedPropertyNames.IsComputed].Value.ToString();
bool.TryParse(value, out isComputed);
}
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
return isComputed;
}
private static bool IsIdentity(DataObjectBase column)
{
string temp;
bool isIdentity = false;
try
{
if (column.ExtendedProperties.Contains(ExtendedPropertyNames.IsIdentity))
{
temp = column.ExtendedProperties[ExtendedPropertyNames.IsIdentity].Value.ToString();
bool.TryParse(temp, out isIdentity);
}
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
return isIdentity;
}
private static bool HasDefaultValue(DataObjectBase column)
{
try
{
if (!column.ExtendedProperties.Contains(ExtendedPropertyNames.DefaultValue))
return false;
string value = column.ExtendedProperties[ExtendedPropertyNames.DefaultValue].Value.ToString();
return !string.IsNullOrEmpty(value);
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
return false;
}
#endregion
}
}

View File

@ -1,370 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Xml.Serialization;
namespace SchemaMapper
{
#region Base
public enum Cardinality
{
ZeroOrOne,
One,
Many
}
public class EntityBase
{
[XmlIgnore]
public bool IsProcessed { get; set; }
}
#endregion
#region Model
[DebuggerDisplay("Context: {ContextName}, Database: {DatabaseName}")]
public class EntityContext : EntityBase
{
public EntityContext()
{
Entities = new EntityCollection();
}
public string ClassName { get; set; }
public string DatabaseName { get; set; }
public EntityCollection Entities { get; set; }
public void RenameEntity(string originalName, string newName)
{
if (originalName == newName)
return;
Debug.WriteLine("Rename Entity '{0}' to '{1}'.", originalName, newName);
foreach (var entity in Entities)
{
if (entity.ClassName == originalName)
entity.ClassName = newName;
foreach (var relationship in entity.Relationships)
{
if (relationship.ThisEntity == originalName)
relationship.ThisEntity = newName;
if (relationship.OtherEntity == originalName)
relationship.OtherEntity = newName;
}
}
}
public void RenameProperty(string entityName, string originalName, string newName)
{
if (originalName == newName)
return;
Debug.WriteLine("Rename Property '{0}' to '{1}' in Entity '{2}'.", originalName, newName, entityName);
foreach (var entity in Entities)
{
if (entity.ClassName == entityName)
{
var property = entity.Properties.ByProperty(originalName);
if (property != null)
property.PropertyName = newName;
}
foreach (var relationship in entity.Relationships)
{
if (relationship.ThisEntity == entityName)
for (int i = 0; i < relationship.ThisProperties.Count; i++)
if (relationship.ThisProperties[i] == originalName)
relationship.ThisProperties[i] = newName;
if (relationship.OtherEntity == entityName)
for (int i = 0; i < relationship.OtherProperties.Count; i++)
if (relationship.OtherProperties[i] == originalName)
relationship.OtherProperties[i] = newName;
}
}
}
}
[DebuggerDisplay("Class: {ClassName}, Table: {FullName}, Context: {ContextName}")]
public class Entity : EntityBase
{
public Entity()
{
Properties = new PropertyCollection();
Relationships = new RelationshipCollection();
Methods = new MethodCollection();
}
public string ContextName { get; set; }
public string ClassName { get; set; }
public string MappingName { get; set; }
public string Description{ get;set;}
public string TableSchema { get; set; }
public string TableName { get; set; }
public string FullName { get; set; }
public PropertyCollection Properties { get; set; }
public RelationshipCollection Relationships { get; set; }
public MethodCollection Methods { get; set; }
}
[DebuggerDisplay("Property: {PropertyName}, Column: {ColumnName}, Type: {NativeType}")]
public class Property : EntityBase
{
public string PropertyName { get; set; }
public string ColumnName { get; set; }
public string Description { get; set; }
public DbType DataType { get; set; }
public string NativeType { get; set; }
[XmlIgnore]
public Type SystemType { get; set; }
public int? Order { get; set; }
public bool OrderSpecified
{
get { return Order.HasValue; }
}
public bool? IsNullable { get; set; }
public bool IsNullableSpecified
{
get { return IsNullable.HasValue; }
}
public bool IsRequired
{
get { return IsNullable == false; }
set { IsNullable = !value; }
}
public bool IsOptional
{
get { return IsNullable == true; }
set { IsNullable = value; }
}
public bool? IsPrimaryKey { get; set; }
public bool IsPrimaryKeySpecified
{
get { return IsPrimaryKey.HasValue; }
}
public bool? IsForeignKey { get; set; }
public bool IsForeignKeySpecified
{
get { return IsForeignKey.HasValue; }
}
public bool? IsAutoGenerated { get; set; }
public bool IsAutoGeneratedSpecified
{
get { return IsAutoGenerated.HasValue; }
}
public bool? IsReadOnly { get; set; }
public bool IsReadOnlySpecified
{
get { return IsReadOnly.HasValue; }
}
public bool? IsRowVersion { get; set; }
public bool IsRowVersionSpecified
{
get { return IsRowVersion.HasValue; }
}
public bool? IsIdentity { get; set; }
public bool IsIdentitySpecified
{
get { return IsIdentity.HasValue; }
}
public bool? IsUnique { get; set; }
public bool IsUniqueSpecified
{
get { return IsUnique.HasValue; }
}
public bool? IsUnicode { get; set; }
public bool IsUnicodeSpecified
{
get { return IsUnicode.HasValue; }
}
public bool? IsFixedLength { get; set; }
public bool IsFixedLengthSpecified
{
get { return IsFixedLength.HasValue; }
}
public int? MaxLength { get; set; }
public bool MaxLengthSpecified
{
get { return MaxLength.HasValue; }
}
public byte? Precision { get; set; }
public bool PrecisionSpecified
{
get { return Precision.HasValue; }
}
public int? Scale { get; set; }
public bool ScaleSpecified
{
get { return Scale.HasValue; }
}
}
[DebuggerDisplay("Other: {OtherEntity}, Property: {OtherPropertyName}, Relationship: {RelationshipName}")]
public class Relationship : EntityBase
{
public Relationship()
{
OtherProperties = new List<string>();
ThisProperties = new List<string>();
}
public string RelationshipName { get; set; }
public string ThisEntity { get; set; }
public string ThisPropertyName { get; set; }
public Cardinality ThisCardinality { get; set; }
public List<string> ThisProperties { get; set; }
public string OtherEntity { get; set; }
public string OtherPropertyName { get; set; }
public Cardinality OtherCardinality { get; set; }
public List<string> OtherProperties { get; set; }
public bool? CascadeDelete { get; set; }
public bool IsForeignKey { get; set; }
public bool IsMapped { get; set; }
public bool IsManyToMany
{
get
{
return ThisCardinality == Cardinality.Many
&& OtherCardinality == Cardinality.Many;
}
}
public bool IsOneToOne
{
get
{
return ThisCardinality != Cardinality.Many
&& OtherCardinality != Cardinality.Many;
}
}
public string JoinTable { get; set; }
public string JoinSchema { get; set; }
public List<string> JoinThisColumn { get; set; }
public List<string> JoinOtherColumn { get; set; }
}
[DebuggerDisplay("Suffix: {NameSuffix}, IsKey: {IsKey}, IsUnique: {IsUnique}")]
public class Method : EntityBase
{
public Method()
{
Properties = new List<Property>();
}
public string NameSuffix { get; set; }
public string SourceName { get; set; }
public bool IsKey { get; set; }
public bool IsUnique { get; set; }
public bool IsIndex { get; set; }
public List<Property> Properties { get; set; }
}
#endregion
#region Collections
public class EntityCollection
: ObservableCollection<Entity>
{
public bool IsProcessed { get; set; }
public Entity ByTable(string fullName)
{
return this.FirstOrDefault(x => x.FullName == fullName);
}
public Entity ByTable(string tableName, string tableSchema)
{
return this.FirstOrDefault(x => x.TableName == tableName && x.TableSchema == tableSchema);
}
public Entity ByClass(string className)
{
return this.FirstOrDefault(x => x.ClassName == className);
}
public Entity ByContext(string contextName)
{
return this.FirstOrDefault(x => x.ContextName == contextName);
}
}
public class PropertyCollection
: ObservableCollection<Property>
{
public bool IsProcessed { get; set; }
public IEnumerable<Property> PrimaryKeys
{
get { return this.Where(p => p.IsPrimaryKey == true); }
}
public IEnumerable<Property> ForeignKeys
{
get { return this.Where(p => p.IsForeignKey == true); }
}
public Property ByColumn(string columnName)
{
return this.FirstOrDefault(x => x.ColumnName == columnName);
}
public Property ByProperty(string propertyName)
{
return this.FirstOrDefault(x => x.PropertyName == propertyName);
}
}
public class RelationshipCollection
: ObservableCollection<Relationship>
{
public bool IsProcessed { get; set; }
public Relationship ByName(string name)
{
return this.FirstOrDefault(x => x.RelationshipName == name);
}
public Relationship ByProperty(string propertyName)
{
return this.FirstOrDefault(x => x.ThisPropertyName == propertyName);
}
public Relationship ByOther(string name)
{
return this.FirstOrDefault(x => x.OtherEntity == name);
}
}
public class MethodCollection
: ObservableCollection<Method>
{
public bool IsProcessed { get; set; }
}
#endregion
}

View File

@ -1,639 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.CSharp;
namespace SchemaMapper
{
#region Mapping Parser
[DebuggerDisplay("Table: {TableName}, Entity: {EntityClass}, Mapping: {MappingClass}")]
public class ParsedEntity
{
public ParsedEntity()
{
Properties = new List<ParsedProperty>();
Relationships = new List<ParsedRelationship>();
}
public string EntityClass { get; set; }
public string MappingClass { get; set; }
public string TableName { get; set; }
public string TableSchema { get; set; }
public List<ParsedProperty> Properties { get; private set; }
public List<ParsedRelationship> Relationships { get; private set; }
}
[DebuggerDisplay("Column: {ColumnName}, Property: {PropertyName}")]
public class ParsedProperty
{
public string ColumnName { get; set; }
public string PropertyName { get; set; }
}
[DebuggerDisplay("This: {ThisPropertyName}, Other: {OtherPropertyName}")]
public class ParsedRelationship
{
public ParsedRelationship()
{
ThisProperties = new List<string>();
JoinThisColumn = new List<string>();
JoinOtherColumn = new List<string>();
}
public string ThisPropertyName { get; set; }
public List<string> ThisProperties { get; private set; }
public string OtherPropertyName { get; set; }
public string JoinTable { get; set; }
public string JoinSchema { get; set; }
public List<string> JoinThisColumn { get; private set; }
public List<string> JoinOtherColumn { get; private set; }
}
public class MappingVisitor : DepthFirstAstVisitor<object, object>
{
public MappingVisitor()
{
MappingBaseType = "EntityTypeConfiguration";
}
public string MappingBaseType { get; set; }
public ParsedEntity ParsedEntity { get; set; }
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
var baseType = typeDeclaration.BaseTypes.OfType<MemberType>().FirstOrDefault();
if (baseType == null || baseType.MemberName != MappingBaseType)
return base.VisitTypeDeclaration(typeDeclaration, data);
var entity = baseType.TypeArguments.OfType<MemberType>().FirstOrDefault();
if (entity == null)
return base.VisitTypeDeclaration(typeDeclaration, data);
if (ParsedEntity == null)
ParsedEntity = new ParsedEntity();
ParsedEntity.EntityClass = entity.MemberName;
ParsedEntity.MappingClass = typeDeclaration.Name;
return base.VisitTypeDeclaration(typeDeclaration, ParsedEntity);
}
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
if (data == null)
return base.VisitInvocationExpression(invocationExpression, null);
// visit all the methods
var identifier = invocationExpression.Target.Children.OfType<Identifier>().FirstOrDefault();
string methodName = identifier == null ? string.Empty : identifier.Name;
// the different types of incoming data, helps us know what we're parsing
var parsedEntity = data as ParsedEntity;
var parsedProperty = data as ParsedProperty;
var parsedRelationship = data as ParsedRelationship;
switch (methodName)
{
case "ToTable":
var tableNameExpression = invocationExpression.Arguments
.OfType<PrimitiveExpression>()
.ToArray();
string tableName = null;
string tableSchema = null;
if (tableNameExpression.Length >= 1)
tableName = tableNameExpression[0].Value.ToString();
if (tableNameExpression.Length >= 2)
tableSchema = tableNameExpression[1].Value.ToString();
// ToTable is either Entity -> Table map or Many to Many map
if (parsedEntity != null)
{
// when data is ParsedEntity, entity map
parsedEntity.TableName = tableName;
parsedEntity.TableSchema = tableSchema;
}
else if (parsedRelationship != null)
{
// when data is ParsedRelationship, many to many map
parsedRelationship.JoinTable = tableName;
parsedRelationship.JoinSchema = tableSchema;
}
break;
case "HasColumnName":
var columnNameExpression = invocationExpression.Arguments
.OfType<PrimitiveExpression>()
.FirstOrDefault();
if (columnNameExpression == null)
break;
// property to column map start.
string columnName = columnNameExpression.Value.ToString();
var property = new ParsedProperty { ColumnName = columnName };
ParsedEntity.Properties.Add(property);
//only have column info at this point. pass data to get property name.
return base.VisitInvocationExpression(invocationExpression, property);
case "Property":
var propertyExpression = invocationExpression.Arguments
.OfType<LambdaExpression>()
.FirstOrDefault();
if (parsedProperty == null || propertyExpression == null)
break;
// ParsedProperty is passed in as data from HasColumnName, add property name
var propertyBodyExpression = propertyExpression.Body as MemberReferenceExpression;
if (propertyBodyExpression != null)
parsedProperty.PropertyName = propertyBodyExpression.MemberName;
break;
case "Map":
// start a new Many to Many relationship
var mapRelation = new ParsedRelationship();
ParsedEntity.Relationships.Add(mapRelation);
// pass to child nodes to fill in data
return base.VisitInvocationExpression(invocationExpression, mapRelation);
case "HasForeignKey":
var foreignExpression = invocationExpression.Arguments
.OfType<LambdaExpression>()
.FirstOrDefault();
if (foreignExpression == null)
break;
// when only 1 fkey, body will be member ref
if (foreignExpression.Body is MemberReferenceExpression)
{
var foreignBodyExpression = foreignExpression.Body as MemberReferenceExpression;
// start a new relationship
var foreignRelation = new ParsedRelationship();
ParsedEntity.Relationships.Add(foreignRelation);
foreignRelation.ThisProperties.Add(foreignBodyExpression.MemberName);
// pass as data for child nodes to fill in data
return base.VisitInvocationExpression(invocationExpression, foreignRelation);
}
// when more then 1 fkey, body will be an anonymous type
if (foreignExpression.Body is AnonymousTypeCreateExpression)
{
var foreignBodyExpression = foreignExpression.Body as AnonymousTypeCreateExpression;
var foreignRelation = new ParsedRelationship();
ParsedEntity.Relationships.Add(foreignRelation);
var properties = foreignBodyExpression.Children
.OfType<MemberReferenceExpression>()
.Select(m => m.MemberName);
foreignRelation.ThisProperties.AddRange(properties);
return base.VisitInvocationExpression(invocationExpression, foreignRelation);
}
break;
case "HasMany":
var hasManyExpression = invocationExpression.Arguments
.OfType<LambdaExpression>()
.FirstOrDefault();
if (parsedRelationship == null || hasManyExpression == null)
break;
// filling existing relationship data
var hasManyBodyExpression = hasManyExpression.Body as MemberReferenceExpression;
if (hasManyBodyExpression != null)
parsedRelationship.ThisPropertyName = hasManyBodyExpression.MemberName;
break;
case "WithMany":
var withManyExpression = invocationExpression.Arguments
.OfType<LambdaExpression>()
.FirstOrDefault();
if (parsedRelationship == null || withManyExpression == null)
break;
// filling existing relationship data
var withManyBodyExpression = withManyExpression.Body as MemberReferenceExpression;
if (withManyBodyExpression != null)
parsedRelationship.OtherPropertyName = withManyBodyExpression.MemberName;
break;
case "HasRequired":
case "HasOptional":
var hasExpression = invocationExpression.Arguments
.OfType<LambdaExpression>()
.FirstOrDefault();
if (parsedRelationship == null || hasExpression == null)
break;
// filling existing relationship data
var hasBodyExpression = hasExpression.Body as MemberReferenceExpression;
if (hasBodyExpression != null)
parsedRelationship.ThisPropertyName = hasBodyExpression.MemberName;
break;
case "MapLeftKey":
if (parsedRelationship == null)
break;
var leftKeyExpression = invocationExpression.Arguments
.OfType<PrimitiveExpression>()
.Select(e => e.Value.ToString());
parsedRelationship.JoinThisColumn.AddRange(leftKeyExpression);
break;
case "MapRightKey":
if (parsedRelationship == null)
break;
var rightKeyExpression = invocationExpression.Arguments
.OfType<PrimitiveExpression>()
.Select(e => e.Value.ToString());
parsedRelationship.JoinOtherColumn.AddRange(rightKeyExpression);
break;
}
return base.VisitInvocationExpression(invocationExpression, data);
}
}
public static class MappingParser
{
public static ParsedEntity Parse(string mappingFile)
{
if (string.IsNullOrEmpty(mappingFile) || !File.Exists(mappingFile))
return null;
var parser = new CSharpParser();
CompilationUnit compilationUnit;
using (var stream = File.OpenText(mappingFile))
compilationUnit = parser.Parse(stream, mappingFile);
var visitor = new MappingVisitor();
visitor.VisitCompilationUnit(compilationUnit, null);
var parsedEntity = visitor.ParsedEntity;
if (parsedEntity != null)
Debug.WriteLine("Parsed Mapping File: '{0}'; Properties: {1}; Relationships: {2}",
Path.GetFileName(mappingFile),
parsedEntity.Properties.Count,
parsedEntity.Relationships.Count);
return parsedEntity;
}
}
#endregion
#region Context Parser
[DebuggerDisplay("Context: {ContextClass}")]
public class ParsedContext
{
public ParsedContext()
{
Properties = new List<ParsedEntitySet>();
}
public string ContextClass { get; set; }
public List<ParsedEntitySet> Properties { get; private set; }
}
[DebuggerDisplay("Entity: {EntityClass}, Property: {ContextProperty}")]
public class ParsedEntitySet
{
public string EntityClass { get; set; }
public string ContextProperty { get; set; }
}
public class ContextVisitor : DepthFirstAstVisitor<object, object>
{
public ContextVisitor()
{
ContextBaseType = "DbContext";
DataSetType = "DbSet";
}
public string ContextBaseType { get; set; }
public string DataSetType { get; set; }
public ParsedContext ParsedContext { get; set; }
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
var baseType = typeDeclaration.BaseTypes
.OfType<MemberType>()
.FirstOrDefault();
// warning: if inherited from custom base type, this will break
// anyway to improve this?
if (baseType == null || baseType.MemberName != ContextBaseType)
return base.VisitTypeDeclaration(typeDeclaration, data);
if (ParsedContext == null)
ParsedContext = new ParsedContext();
ParsedContext.ContextClass = typeDeclaration.Name;
return base.VisitTypeDeclaration(typeDeclaration, ParsedContext);
}
public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
{
if (data == null)
return base.VisitPropertyDeclaration(propertyDeclaration, null);
// look for property to return generic DbSet type
var memberType = propertyDeclaration.ReturnType as MemberType;
if (memberType == null || memberType.MemberName != DataSetType)
return base.VisitPropertyDeclaration(propertyDeclaration, data);
// get the first generic type
var entityType = memberType.TypeArguments
.OfType<MemberType>()
.FirstOrDefault();
if (entityType == null)
return base.VisitPropertyDeclaration(propertyDeclaration, data);
var entitySet = new ParsedEntitySet
{
EntityClass = entityType.MemberName,
ContextProperty = propertyDeclaration.Name
};
ParsedContext.Properties.Add(entitySet);
return base.VisitPropertyDeclaration(propertyDeclaration, data);
}
}
public static class ContextParser
{
public static ParsedContext Parse(string contextFile)
{
if (string.IsNullOrEmpty(contextFile) || !File.Exists(contextFile))
return null;
var parser = new CSharpParser();
CompilationUnit compilationUnit;
using (var stream = File.OpenText(contextFile))
compilationUnit = parser.Parse(stream, contextFile);
var visitor = new ContextVisitor();
visitor.VisitCompilationUnit(compilationUnit, null);
var parsedContext = visitor.ParsedContext;
if (parsedContext != null)
Debug.WriteLine("Parsed Context File: '{0}'; Entities: {1}",
Path.GetFileName(contextFile),
parsedContext.Properties.Count);
return parsedContext;
}
}
#endregion
public static class Synchronizer
{
public static bool UpdateFromSource(EntityContext generatedContext, string contextDirectory, string mappingDirectory)
{
if (generatedContext == null)
return false;
// make sure to update the entities before the context
UpdateFromMapping(generatedContext, mappingDirectory);
UpdateFromContext(generatedContext, contextDirectory);
return true;
}
private static void UpdateFromContext(EntityContext generatedContext, string contextDirectory)
{
if (generatedContext == null
|| contextDirectory == null
|| !Directory.Exists(contextDirectory))
return;
// parse context
ParsedContext parsedContext = null;
var files = Directory.EnumerateFiles(contextDirectory, "*.Generated.cs").GetEnumerator();
while (files.MoveNext() && parsedContext == null)
parsedContext = ContextParser.Parse(files.Current);
if (parsedContext == null)
return;
if (generatedContext.ClassName != parsedContext.ContextClass)
{
Debug.WriteLine("Rename Context Class'{0}' to '{1}'.",
generatedContext.ClassName,
parsedContext.ContextClass);
generatedContext.ClassName = parsedContext.ContextClass;
}
foreach (var parsedProperty in parsedContext.Properties)
{
var entity = generatedContext.Entities.ByClass(parsedProperty.EntityClass);
if (entity == null)
continue;
if (entity.ContextName == parsedProperty.ContextProperty)
continue;
Debug.WriteLine("Rename Context Property'{0}' to '{1}'.",
entity.ContextName,
parsedProperty.ContextProperty);
entity.ContextName = parsedProperty.ContextProperty;
}
}
private static void UpdateFromMapping(EntityContext generatedContext, string mappingDirectory)
{
if (generatedContext == null
|| mappingDirectory == null
|| !Directory.Exists(mappingDirectory))
return;
// parse all mapping files
var mappingFiles = Directory.EnumerateFiles(mappingDirectory, "*.Generated.cs");
var parsedEntities = mappingFiles
.Select(MappingParser.Parse)
.Where(parsedEntity => parsedEntity != null)
.ToList();
var relationshipQueue = new List<Tuple<Entity, ParsedEntity>>();
// update all entity and property names first because relationships are linked by property names
foreach (var parsedEntity in parsedEntities)
{
// find entity by table name to support renaming entity
var entity = generatedContext.Entities
.ByTable(parsedEntity.TableName, parsedEntity.TableSchema);
if (entity == null)
continue;
// sync names
if (entity.MappingName != parsedEntity.MappingClass)
{
Debug.WriteLine("Rename Mapping Class'{0}' to '{1}'.",
entity.MappingName,
parsedEntity.MappingClass);
entity.MappingName = parsedEntity.MappingClass;
}
// use rename api to make sure all instances are renamed
generatedContext.RenameEntity(entity.ClassName, parsedEntity.EntityClass);
// sync properties
foreach (var parsedProperty in parsedEntity.Properties)
{
// find property by column name to support property name rename
var property = entity.Properties.ByColumn(parsedProperty.ColumnName);
if (property == null)
continue;
// use rename api to make sure all instances are renamed
generatedContext.RenameProperty(
entity.ClassName,
property.PropertyName,
parsedProperty.PropertyName);
}
// save relationship for later processing
var item = new Tuple<Entity, ParsedEntity>(entity, parsedEntity);
relationshipQueue.Add(item);
}
// update relationships last
foreach (var tuple in relationshipQueue)
UpdateRelationships(generatedContext, tuple.Item1, tuple.Item2);
}
private static void UpdateRelationships(EntityContext generatedContext, Entity entity, ParsedEntity parsedEntity)
{
// sync relationships
foreach (var parsedRelationship in parsedEntity.Relationships.Where(r => r.JoinTable == null))
{
var parsedProperties = parsedRelationship.ThisProperties;
var relationship = entity.Relationships
.Where(r => !r.IsManyToMany)
.FirstOrDefault(r => r.ThisProperties.Except(parsedProperties).Count() == 0);
if (relationship == null)
continue;
bool isThisSame = relationship.ThisPropertyName == parsedRelationship.ThisPropertyName;
bool isOtherSame = relationship.OtherPropertyName == parsedRelationship.OtherPropertyName;
if (isThisSame && isOtherSame)
continue;
if (!isThisSame)
{
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
relationship.ThisEntity,
relationship.ThisPropertyName,
parsedRelationship.ThisPropertyName);
relationship.ThisPropertyName = parsedRelationship.ThisPropertyName;
}
if (!isOtherSame)
{
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
relationship.OtherEntity,
relationship.OtherPropertyName,
parsedRelationship.OtherPropertyName);
relationship.OtherPropertyName = parsedRelationship.OtherPropertyName;
}
// sync other relationship
var otherEntity = generatedContext.Entities.ByClass(relationship.OtherEntity);
if (otherEntity == null)
continue;
var otherRelationship = otherEntity.Relationships.ByName(relationship.RelationshipName);
if (otherRelationship == null)
continue;
otherRelationship.ThisPropertyName = relationship.OtherPropertyName;
otherRelationship.OtherPropertyName = relationship.ThisPropertyName;
}
// sync many to many
foreach (var parsedRelationship in parsedEntity.Relationships.Where(r => r.JoinTable != null))
{
var joinThisColumn = parsedRelationship.JoinThisColumn;
var joinOtherColumn = parsedRelationship.JoinOtherColumn;
var relationship = entity.Relationships
.Where(r => r.IsManyToMany)
.FirstOrDefault(r =>
r.JoinThisColumn.Except(joinThisColumn).Count() == 0 &&
r.JoinOtherColumn.Except(joinOtherColumn).Count() == 0 &&
r.JoinTable == parsedRelationship.JoinTable &&
r.JoinSchema == parsedRelationship.JoinSchema);
if (relationship == null)
continue;
bool isThisSame = relationship.ThisPropertyName == parsedRelationship.ThisPropertyName;
bool isOtherSame = relationship.OtherPropertyName == parsedRelationship.OtherPropertyName;
if (isThisSame && isOtherSame)
continue;
if (!isThisSame)
{
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
relationship.ThisEntity,
relationship.ThisPropertyName,
parsedRelationship.ThisPropertyName);
relationship.ThisPropertyName = parsedRelationship.ThisPropertyName;
}
if (!isOtherSame)
{
Debug.WriteLine("Rename Relationship Property '{0}.{1}' to '{0}.{2}'.",
relationship.OtherEntity,
relationship.OtherPropertyName,
parsedRelationship.OtherPropertyName);
relationship.OtherPropertyName = parsedRelationship.OtherPropertyName;
}
// sync other relationship
var otherEntity = generatedContext.Entities.ByClass(relationship.OtherEntity);
if (otherEntity == null)
continue;
var otherRelationship = otherEntity.Relationships.ByName(relationship.RelationshipName);
if (otherRelationship == null)
continue;
otherRelationship.ThisPropertyName = relationship.OtherPropertyName;
otherRelationship.OtherPropertyName = relationship.ThisPropertyName;
}
}
}
}

View File

@ -1,105 +0,0 @@
<%--
Name: Database Table Properties
Author: yubaolee
Description: Create a list of properties from a database table
--%>
<%@ CodeTemplate Language="C#" Encoding="utf-8" TargetLanguage="C#" Debug="False" Description="控制器" %>
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
using System;
using System.Collections.Generic;
using System.Linq;
using Infrastructure;
using Microsoft.AspNetCore.Mvc;
using OpenAuth.App;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.Repository.Domain;
namespace OpenAuth.Mvc.Controllers
{
public class <%=ModuleName%>sController : BaseController
{
private readonly <%=ModuleName%>App _app;
public <%=ModuleName%>sController(<%=ModuleName%>App app, IAuth auth) : base(auth)
{
_app = app;
}
//主页
public ActionResult Index()
{
return View();
}
/// <summary>
/// MVC界面添加
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
[HttpPost]
public string Add(AddOrUpdate<%=ModuleName%>Req obj)
{
try
{
_app.Add(obj);
}
catch (Exception ex)
{
Result.Code = 500;
Result.Message = ex.Message;
}
return JsonHelper.Instance.Serialize(Result);
}
/// <summary>
/// MVC界面修改
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
[HttpPost]
public string Update(AddOrUpdate<%=ModuleName%>Req obj)
{
try
{
_app.Update(obj);
}
catch (Exception ex)
{
Result.Code = 500;
Result.Message = ex.Message;
}
return JsonHelper.Instance.Serialize(Result);
}
/// <summary>
/// 加载列表
/// </summary>
public string Load([FromQuery]Query<%=ModuleName%>ListReq request)
{
return JsonHelper.Instance.Serialize(_app.Load(request));
}
[HttpPost]
public string Delete(string[] ids)
{
try
{
_app.Delete(ids);
}
catch (Exception e)
{
Result.Code = 500;
Result.Message = e.Message;
}
return JsonHelper.Instance.Serialize(Result);
}
}
}

View File

@ -1,94 +0,0 @@
<%--
Name: 列表页面
Author: yubaolee
Description: 列表页面
--%>
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Debug="False" Encoding="utf-8" Description="添加模块" %>
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context"
Description="连接的数据库" %>
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Assembly Src="Util.cs" %>
<%@ Import Namespace="Util" %>
@section header
{
}
<blockquote class="layui-elem-quote news_search toolList" id="menus">
</blockquote>
<div class="layui-card">
<table class="layui-table" id="mainList"
lay-data="{height: 'full-80', page:true, id:'mainList'}"
lay-filter="list" lay-size="sm">
</table>
<script type="text/html" id="Disable">
{{# if(d.Disable){ }}
<span class="layui-badge">已禁用</span>
{{# } else{}}
<span class="layui-badge layui-bg-green">正常</span>
{{# } }}
</script>
</div>
<!--添加/编辑窗口-->
<div id="divEdit" style="display: none">
<form class="layui-form" action="" id="formEdit" lay-filter="formEdit">
<% foreach (ColumnSchema column in this.SourceTable.Columns) {
var typename = CSharpAlias[column.SystemType.FullName];
//Response.WriteLine(typename);
if(column.IsPrimaryKeyMember){%>
<input type="hidden" name="<%=column.Name%>" />
<%}else if(CSharpAlias[column.SystemType.FullName] == "bool") {%>
<div class="layui-form-item">
<label class="layui-form-label"><%=Tools.GetDescription(column)%></label>
<div class="layui-input-block">
<input type="checkbox" name="<%=column.Name%>" lay-skin="switch" value="1">
</div>
</div>
<%}else if(CSharpAlias[column.SystemType.FullName] == "System.DateTime") {%>
<div class="layui-form-item">
<label class="layui-form-label"><%=Tools.GetDescription(column)%></label>
<div class="layui-input-block">
<input type="text" name="<%=column.Name%>" id="<%=column.Name%>" lay-verify="date" placeholder="yyyy-MM-dd" autocomplete="off" class="layui-input">
</div>
</div>
<%}else if(CSharpAlias[column.SystemType.FullName] == "int" ) {%>
<div class="layui-form-item">
<label class="layui-form-label"><%=Tools.GetDescription(column)%></label>
<div class="layui-input-block">
<input type="number" name="<%=column.Name%>" placeholder="" autocomplete="off" class="layui-input" min="0" step="1" lay-affix="number">
</div>
</div>
<%} else {%>
<div class="layui-form-item">
<label class="layui-form-label"><%=Tools.GetDescription(column)%></label>
<div class="layui-input-block">
<input type="text" name="<%=column.Name%>" required lay-verify="required"
placeholder="<%=Tools.GetDescription(column)%>" autocomplete="off" class="layui-input">
</div>
</div>
<%} %>
<%} %>
<%if(Tools.NeedCascade(SourceTable)){ %>
<div class="layui-form-item">
<label class="layui-form-label">所属部门</label>
<div class="layui-input-block">
<input id="Organizations" name="Organizations" v-model="Organizations" required lay-verify="required" class="layui-input" />
<input id="OrganizationIds" name="OrganizationIds" v-model="OrganizationIds" required lay-verify="required" type="hidden" />
<div id="menuContent" class="menuContent" style="display: none;">
<ul id="org" class="ztree"></ul>
</div>
</div>
</div>
<%} %>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formSubmit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
<script type="text/javascript" src="/layui/layui.js"></script>
<script type="text/javascript" src="/userJs/<%=ModuleName.ToLower()%>s.js"></script>

View File

@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using CodeSmith.Engine;
using SchemaExplorer;
namespace Util{
public class Tools{
public static String GetDescription(ColumnSchema column) { //得到字段的描述
if(string.IsNullOrEmpty(column.Description))
return column.Name;
else
return column.Description;
}
public static bool NeedCascade(TableSchema SourceTable){ //判断表中是否需要下拉选择树
return SourceTable.Columns.Contains("ParentId")
|| SourceTable.Columns.Contains("CascadeId") ;
}
public static string CreateBlank(int level){
if(level == 1){
return " ";
}
else{
var twoblanks = " ";
for (int i = level-1; i > 1; i--)
{
twoblanks +=twoblanks;
}
return CreateBlank(1) + twoblanks;
}
}
}
}

View File

@ -1,181 +0,0 @@
<%--
Name: 主JS界面
Author: yubaolee
--%>
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Debug="False" Encoding="utf-8" Description="添加模块" %>
<%@ Property Name="ModuleName" Type="String" Category="Context" Description="模块名称" %>
<%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="Context"
Description="连接的数据库" %>
<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Assembly Src="Util.cs" %>
<%@ Import Namespace="Util" %>
layui.config({
base: "/js/"
}).use(['form', 'laydate', 'ztree', 'layer', 'jquery', 'table', 'droptree', 'openauth', 'utils'], function () {
var form = layui.form,
layer = layui.layer,
laydate = layui.laydate,
$ = layui.jquery;
var table = layui.table;
var openauth = layui.openauth;
var toplayer = (top == undefined || top.layer === undefined) ? layer : top.layer; //顶层的LAYER
$("#menus").loadMenus("<%=ModuleName%>");
<% foreach (ColumnSchema column in this.SourceTable.Columns) {
if(CSharpAlias[column.SystemType.FullName] == "System.DateTime") { %>
laydate.render({
elem: '#<%=column.Name%>'
});
<%} }%>
var initVal = { //初始化的值
<% foreach (ColumnSchema column in this.SourceTable.Columns) {
if(CSharpAlias[column.SystemType.FullName] == "bool") { %>
<%=column.Name%>: false,
<%}else if(CSharpAlias[column.SystemType.FullName] == "int" ) {%>
<%=column.Name%>: 0,
<%}else if(CSharpAlias[column.SystemType.FullName] == "System.DateTime") {%>
<%=column.Name%>: new Date().toISOString().split('T')[0],
<%} else {%>
<%=column.Name%>: '',
<%} }%>
}
//加载表头
$.getJSON('/<%=ModuleName%>s/Load',
{ page: 1, limit: 1 },
function (data) {
var columns = data.columnFields.filter(u => u.IsList ===true).map(function (e) {
return {
field: e.ColumnName,
title: e.Remark
};
});
columns.unshift({
type: 'checkbox',
fixed: 'left'
});
table.render({
elem: '#mainList',
page: true,
url: '/<%=ModuleName%>s/Load',
cols: [columns]
, response: {
statusCode: 200 //规定成功的状态码默认0
}
});
});
//主列表加载,可反复调用进行刷新
var config = {}; //table的参数如搜索key点击tree的id
var mainList = function(options) {
if (options != undefined) {
$.extend(config, options);
}
table.reload('mainList',
{
url: '/<%=ModuleName%>s/Load',
where: config
, response: {
statusCode: 200 //规定成功的状态码默认0
}
});
};
mainList();
//添加(编辑)对话框
var editDlg = function () {
var show = function (update, data) {
var title = update ? "编辑信息" : "添加";
layer.open({
title: title,
area: ["500px", "400px"],
type: 1,
content: $('#divEdit'),
success: function () {
if(data == undefined){
form.val("formEdit", initVal);
}else{
form.val("formEdit", data);
}
},
end: mainList
});
var url = "/<%=ModuleName%>s/Add";
if (update) {
url = "/<%=ModuleName%>s/Update";
}
//提交数据
form.on('submit(formSubmit)',
function (data) {
$.post(url,
data.field,
function (data) {
layer.msg(data.Message);
},
"json");
return false;
});
}
return {
add: function () { //弹出添加
show(false);
},
update: function (data) { //弹出编辑框
show(true, data);
}
};
}();
//监听表格内部按钮
table.on('tool(list)', function (obj) {
var data = obj.data;
if (obj.event === 'detail') { //查看
layer.msg('ID' + data.Id + ' 的查看操作');
}
});
//监听页面主按钮操作
var active = {
btnDel: function () { //批量删除
var checkStatus = table.checkStatus('mainList')
, data = checkStatus.data;
openauth.del("/<%=ModuleName%>s/Delete",
data.map(function (e) { return e.Id; }),
mainList);
}
, btnAdd: function () { //添加
editDlg.add();
}
, btnEdit: function () { //编辑
var checkStatus = table.checkStatus('mainList')
, data = checkStatus.data;
if (data.length != 1) {
layer.msg("请选择编辑的行,且同时只能编辑一行");
return;
}
editDlg.update(data[0]);
}
, search: function () { //搜索
mainList({ key: $('#key').val() });
}
, btnRefresh: function () {
mainList();
}
};
$('.toolList .layui-btn').on('click', function () {
var type = $(this).data('type');
active[type] ? active[type].call(this) : '';
});
//监听页面主按钮操作 end
})

View File

@ -1,130 +0,0 @@
<%--
Author: yubaolee
Description: 用于生成OpenAuth.Core开源版前端Web界面包括mvc controller/csthml/js
--%>
<%@ Template Language="C#" TargetLanguage="Text" Debug="True" OutputType="None" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Assembly Name="CodeSmith.CustomProperties" %>
<%@ Assembly Name="Mono.Cecil" Path="..\Common" %>
<%@ Assembly Name="ICSharpCode.NRefactory" Path="..\Common" %>
<%@ Assembly Name="ICSharpCode.NRefactory.CSharp" Path="..\Common" %>
<%@ Assembly Src="Internal\Model.cs" %>
<%@ Assembly Src="Internal\Extensions.cs" %>
<%@ Assembly Src="Internal\Generator.cs" %>
<%@ Assembly Src="Internal\Parser.cs" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>
<%@ Import Namespace="SchemaMapper" %>
<%@ Property Name="SourceTable"
Type="SchemaExplorer.TableSchema"
Category="Context"
Description="连接的数据库"
OnChanged="OnSourceDatabaseChanged"%>
<%@ Property Name="ModuleName"
Type="System.String"
Description="模块名称User"%>
<%@ Property Name="directory"
Type="System.String"
Default=".\"
Optional="True"
Description="代码生成路径"
Editor="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>
<%@ Register Name="HtmlGenerateClass"
Template="Web\Index.cshtml.cst"
MergeProperties="False" %>
<%@ Register Name="JSGenerateClass"
Template="Web\index.js.cst"
MergeProperties="False" %>
<%@ Register Name="ControllerGenerateClass"
Template="Web\Controller.cst"
MergeProperties="False" %>
Generating Entities ...
<% Generate(); %>
<script runat="template">
public void Generate()
{
Stopwatch watch = Stopwatch.StartNew();
string outputDirectory = Path.GetFullPath(directory);
CreateControllerClass();
CreateHtmlClass();
CreateJSClass();
this.RegisterReference("System.Configuration");
this.RegisterReference("System.Data");
this.RegisterReference("System.Data.Entity");
this.RegisterReference("System.Runtime.Serialization");
this.RegisterReference("EntityFramework");
watch.Stop();
Response.WriteLine("Generate Time: " + watch.ElapsedMilliseconds + " ms");
}
//创建控制器,如UserManagerController.cs
public void CreateControllerClass()
{
ControllerGenerateClass generatedClass = this.Create<ControllerGenerateClass>();
this.CopyPropertiesTo(generatedClass);
string rootDirectory = Path.GetFullPath(directory);
string generatedFile = Path.GetFullPath(directory) + "/Controllers/"+ ModuleName + "sController.cs";
generatedClass.ModuleName = ModuleName;
Response.WriteLine(generatedFile);
generatedClass.RenderToFile(generatedFile, generatedFile, true);
}
//创建视图,如views/Users/index.html
public void CreateHtmlClass()
{
HtmlGenerateClass generatedClass = this.Create<HtmlGenerateClass>();
this.CopyPropertiesTo(generatedClass);
string generatedFile = Path.GetFullPath(directory) + "/Views/"+ModuleName+"s/index.cshtml";
generatedClass.ModuleName = ModuleName;
generatedClass.SourceTable = SourceTable;
Response.WriteLine(generatedFile);
generatedClass.RenderToFile(generatedFile, generatedFile, true);
}
//创建视图,如js/userManager.js
public void CreateJSClass()
{
JSGenerateClass generatedClass = this.Create<JSGenerateClass>();
this.CopyPropertiesTo(generatedClass);
string generatedFile = Path.GetFullPath(directory) + "/userJs/"+ModuleName.ToLower()+"s.js";
generatedClass.ModuleName = ModuleName;
Response.WriteLine(generatedFile);
generatedClass.RenderToFile(generatedFile, generatedFile, true);
}
//更换数据源时改变ModuleName
private void OnSourceDatabaseChanged(object sender, EventArgs e)
{
if (SourceTable == null)
return;
ModuleName = SourceTable.Name;
}
</script>

Binary file not shown.

View File

@ -36,9 +36,7 @@
#### 开源版本
* 开源Vue2演示地址 http://demo.openauth.net.cn:1803
* 开源MVC演示地址http://demo.openauth.net.cn:1802
* 演示地址: http://demo.openauth.net.cn:1803
#### 付费订阅

View File

@ -1,7 +1,7 @@
<!--
* @Author: yubaolee <yubaolee@163.com> | ahfu~ <954478625@qq.com>
* @Date: 2021-06-01 14:10:29
* @LastEditTime: 2025-03-22 13:49:58
* @LastEditTime: 2025-06-07 23:54:30
* @Description:
* @
* @Copyright (c) 2022 by yubaolee | ahfu~ , All Rights Reserved.
@ -17,7 +17,7 @@
<el-card class="box-card">
<el-tag type="danger">一些说明</el-tag>
<p></p>
开源版演示地址<a href="http://demo.openauth.net.cn:1802">http://demo.openauth.net.cn:1802</a>
开源版演示地址<a href="http://demo.openauth.net.cn:1803">http://demo.openauth.net.cn:1803</a>
<p></p>
官方网址<a href="http://openauth.net.cn">http://openauth.net.cn</a>
<p></p>