diff --git a/CodeSmith/CSharp/Entity.cst b/CodeSmith/CSharp/Entity.cst index 819211ce..90952b98 100644 --- a/CodeSmith/CSharp/Entity.cst +++ b/CodeSmith/CSharp/Entity.cst @@ -1,309 +1,309 @@ -<%@ 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="SourceDatabase" - Type="SchemaExplorer.DatabaseSchema" - Category="1.Database" - OnChanged="OnSourceDatabaseChanged" - Description="The source database." %> - -<%@ Property Name="ContextNamespace" - Type="System.String" - Category="2.Class" - OnChanged="OnContextNamespaceChanged" - Description="The namespace to use for the data context class files."%> -<%@ Property Name="EntityNamespace" - Type="System.String" - Category="2.Class" - Description="The namespace to use for the entity class files."%> -<%@ Property Name="MappingNamespace" - Type="System.String" - Category="2.Class" - Description="The namespace to use for the mapping class files."%> - -<%@ Property Name="ContextDirectory" - Category="3.Output" - Type="System.String" - Default=".\" - Optional="True" - Description="The folder to save the generated context files." - Editor="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %> -<%@ Property Name="EntityDirectory" - Category="3.Output" - Type="System.String" - Default=".\Entities" - Optional="True" - Description="The folder to save the generated entity files." - Editor="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %> -<%@ Property Name="MappingDirectory" - Category="3.Output" - Type="System.String" - Default=".\Mapping" - Optional="True" - Description="The folder to save the generated mapping files." - Editor="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %> - -<%@ Property Name="TableNaming" - Type="SchemaMapper.TableNaming" - Category="4.Hints" - Default="Singular" - Description="Provide generator a hint as to how the tables are named." %> -<%@ Property Name="EntityNaming" - Type="SchemaMapper.EntityNaming" - Category="4.Hints" - Default="Singular" - Description="Tell generator how the entities are to be named." %> -<%@ Property Name="RelationshipNaming" - Type="SchemaMapper.RelationshipNaming" - Category="4.Hints" - Default="Plural" - Description="Tell generator how the relationships are to be named." %> -<%@ Property Name="ContextNaming" - Type="SchemaMapper.ContextNaming" - Category="4.Hints" - Default="Plural" - Description="Tell generator how the context properties are to be named." %> - -<%@ Property Name="IgnoreList" - Type="CodeSmith.CustomProperties.StringCollection" - Category="5.Customization" - Default="sysdiagrams$" - Optional="True" - Description="List of regular expressions to ignore tables, views and commands when generating mapping." %> -<%@ Property Name="InclusionMode" - Type="Boolean" - Category="5.Customization" - Default="False" - Optional="True" - Description="Change the IgnoreList to be a list of table to include instead of ignore." %> -<%@ Property Name="CleanExpressions" - Type="CodeSmith.CustomProperties.StringCollection" - Category="5.Customization" - Default="^(sp|tbl|udf|vw)_" - Optional="True" - Description="List of regular expressions to clean table, view and column names." %> -<%@ Property Name="InterfaceMode" - Type="Boolean" - Category="5.Customization" - Default="False" - Optional="True" - Description="Use interfaces for DbContext." %> - - - -<%@ Register Name="ContextGeneratedClass" - Template="Internal\Context.Generated.cst" - MergeProperties="False" %> - -<%@ Register Name="EntityGeneratedClass" - Template="Internal\Entity.Generated.cst" - MergeProperties="False" %> - -<%@ Register Name="MappingGeneratedClass" - Template="Internal\Mapping.Generated.cst" - MergeProperties="False" %> - -Generating Entities ... -<% Generate(); %> - - \ No newline at end of file diff --git a/CodeSmith/CSharp/Internal/Context.Generated.cst b/CodeSmith/CSharp/Internal/Context.Generated.cst index df3d3a21..a3539d79 100644 --- a/CodeSmith/CSharp/Internal/Context.Generated.cst +++ b/CodeSmith/CSharp/Internal/Context.Generated.cst @@ -1,89 +1,89 @@ -<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %> - -<%@ Assembly Src="Model.cs" %> -<%@ Assembly Src="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="EntityContext" Type="SchemaMapper.EntityContext" %> - -<%@ Property Name="ContextNamespace" Type="System.String" %> -<%@ Property Name="EntityNamespace" Type="System.String" %> -<%@ Property Name="MappingNamespace" Type="System.String" %> -<%@ Property Name="InterfaceMode" Type="Boolean" Default="False" Optional="True" %> - -//------------------------------------------------------------------------------ -// -// 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. -// -//------------------------------------------------------------------------------ -using System; -using System.Data.Entity; -using System.Collections.Generic; -using <%= EntityNamespace %>; -using <%= MappingNamespace %>; - -namespace <%= ContextNamespace %> -{ -<% if (InterfaceMode) { %> - public interface IDbContext : IDisposable - { - System.Data.Entity.Database Database { get; } - System.Data.Entity.Infrastructure.DbChangeTracker ChangeTracker { get; } - System.Data.Entity.Infrastructure.DbContextConfiguration Configuration { get; } - - System.Data.Entity.Infrastructure.DbEntityEntry Entry(object entity); - System.Data.Entity.Infrastructure.DbEntityEntry Entry(TEntity entity) where TEntity : class; - - IEnumerable GetValidationErrors(); - - System.Data.Entity.DbSet Set(Type entityType); - System.Data.Entity.IDbSet Set() where TEntity : class; - - int SaveChanges(); - } - - public partial interface I<%= EntityContext.ClassName.ToSafeName() %> : IDbContext - { -<% foreach(var p in EntityContext.Entities) { %> - System.Data.Entity.IDbSet<<%= EntityNamespace %>.<%= p.ClassName.ToSafeName() %>> <%= p.ContextName.ToSafeName() %> { get; set; } -<% } // foreach %> - } - -<% } // if interface %> - public partial class <%= EntityContext.ClassName.ToSafeName() %>: DbContext<%= InterfaceMode ? ", I" + EntityContext.ClassName.ToSafeName() : string.Empty %> - { - static <%= EntityContext.ClassName.ToSafeName() %>() - { - Database.SetInitializer< <%= EntityContext.ClassName.ToSafeName() %>>(null); - } - public <%= EntityContext.ClassName.ToSafeName() %>() - :base("Name=<%= EntityContext.ClassName.ToSafeName() %>") - { } - - public <%= EntityContext.ClassName.ToSafeName() %>(string nameOrConnectionString) - : base(nameOrConnectionString) - { } - -<% foreach(var p in EntityContext.Entities) { %> - public System.Data.Entity.<%= InterfaceMode ? "I" : "" %>DbSet<<%= p.ClassName.ToSafeName() %>> <%= p.ContextName.ToSafeName() %> { get; set; } -<% } // foreach %> - - -<% if (InterfaceMode) { %> - - System.Data.Entity.IDbSet IDbContext.Set() - { - return base.Set(); - } -<% } // if interface %> - } +<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %> + +<%@ Assembly Src="Model.cs" %> +<%@ Assembly Src="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="EntityContext" Type="SchemaMapper.EntityContext" %> + +<%@ Property Name="ContextNamespace" Type="System.String" %> +<%@ Property Name="EntityNamespace" Type="System.String" %> +<%@ Property Name="MappingNamespace" Type="System.String" %> +<%@ Property Name="InterfaceMode" Type="Boolean" Default="False" Optional="True" %> + +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ +using System; +using System.Data.Entity; +using System.Collections.Generic; +using <%= EntityNamespace %>; +using <%= MappingNamespace %>; + +namespace <%= ContextNamespace %> +{ +<% if (InterfaceMode) { %> + public interface IDbContext : IDisposable + { + System.Data.Entity.Database Database { get; } + System.Data.Entity.Infrastructure.DbChangeTracker ChangeTracker { get; } + System.Data.Entity.Infrastructure.DbContextConfiguration Configuration { get; } + + System.Data.Entity.Infrastructure.DbEntityEntry Entry(object entity); + System.Data.Entity.Infrastructure.DbEntityEntry Entry(TEntity entity) where TEntity : class; + + IEnumerable GetValidationErrors(); + + System.Data.Entity.DbSet Set(Type entityType); + System.Data.Entity.IDbSet Set() where TEntity : class; + + int SaveChanges(); + } + + public partial interface I<%= EntityContext.ClassName.ToSafeName() %> : IDbContext + { +<% foreach(var p in EntityContext.Entities) { %> + System.Data.Entity.IDbSet<<%= EntityNamespace %>.<%= p.ClassName.ToSafeName() %>> <%= p.ContextName.ToSafeName() %> { get; set; } +<% } // foreach %> + } + +<% } // if interface %> + public partial class <%= EntityContext.ClassName.ToSafeName() %>: DbContext<%= InterfaceMode ? ", I" + EntityContext.ClassName.ToSafeName() : string.Empty %> + { + static <%= EntityContext.ClassName.ToSafeName() %>() + { + Database.SetInitializer< <%= EntityContext.ClassName.ToSafeName() %>>(null); + } + public <%= EntityContext.ClassName.ToSafeName() %>() + :base("Name=<%= EntityContext.ClassName.ToSafeName() %>") + { } + + public <%= EntityContext.ClassName.ToSafeName() %>(string nameOrConnectionString) + : base(nameOrConnectionString) + { } + +<% foreach(var p in EntityContext.Entities) { %> + public System.Data.Entity.<%= InterfaceMode ? "I" : "" %>DbSet<<%= p.ClassName.ToSafeName() %>> <%= p.ContextName.ToSafeName() %> { get; set; } +<% } // foreach %> + + +<% if (InterfaceMode) { %> + + System.Data.Entity.IDbSet IDbContext.Set() + { + return base.Set(); + } +<% } // if interface %> + } } \ No newline at end of file diff --git a/CodeSmith/CSharp/Internal/Entity.Generated.cst b/CodeSmith/CSharp/Internal/Entity.Generated.cst index d387ffed..632d50d9 100644 --- a/CodeSmith/CSharp/Internal/Entity.Generated.cst +++ b/CodeSmith/CSharp/Internal/Entity.Generated.cst @@ -1,72 +1,72 @@ -<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %> - -<%@ Assembly Src="Model.cs" %> -<%@ Assembly Src="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="Entity" - Type="SchemaMapper.Entity" %> - -<%@ Property Name="EntityNamespace" - Type="System.String" %> -//------------------------------------------------------------------------------ -// -// 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 -// -//------------------------------------------------------------------------------ -using System; -using System.Collections.Generic; -using System.Text; - -namespace <%= EntityNamespace %> -{ - /// - /// <%= Entity.Description %> - /// - public partial class <%= Entity.ClassName.ToSafeName() %> : Entity - { - public <%= Entity.ClassName.ToSafeName() %>() - { -<% foreach(var p in Entity.Properties) { - if(p.IsPrimaryKey ==true) continue; - string type = p.SystemType.ToNullableType(p.IsNullable == true); - if(type =="int" || type=="decimal") - Response.WriteLine(" this."+p.PropertyName.ToSafeName()+"= 0;"); - else if(type =="string") - Response.WriteLine(" this."+p.PropertyName.ToSafeName()+"= string.Empty;"); - else if(type.ToLower().Contains("datetime")) - Response.WriteLine(" this."+p.PropertyName.ToSafeName()+"= DateTime.Now;"); - } // foreach %> -<% foreach(var r in Entity.Relationships.Where(e => e.ThisCardinality == Cardinality.Many)) { %> - <%= r.ThisPropertyName.ToSafeName() %> = new List<<%= r.OtherEntity.ToSafeName() %>>(); -<% } // foreach %> - } - -<% foreach(var p in Entity.Properties) { - if(p.IsPrimaryKey ==true) continue; - %> - /// - /// <%=p.Description %> - /// - public <%= p.SystemType.ToNullableType(p.IsNullable == true) %> <%= p.PropertyName.ToSafeName() %> { get; set; } -<% } // foreach %> - -<% foreach(var r in Entity.Relationships) { %> -<% if(r.ThisCardinality == Cardinality.Many) { %> - public virtual ICollection<<%= r.OtherEntity.ToSafeName() %>> <%= r.ThisPropertyName.ToSafeName() %> { get; set; } -<% } else { %> - public virtual <%= r.OtherEntity.ToSafeName() %> <%= r.ThisPropertyName.ToSafeName() %> { get; set; } -<% } %> -<% } // foreach %> - } +<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %> + +<%@ Assembly Src="Model.cs" %> +<%@ Assembly Src="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="Entity" + Type="SchemaMapper.Entity" %> + +<%@ Property Name="EntityNamespace" + Type="System.String" %> +//------------------------------------------------------------------------------ +// +// 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 +// +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Text; + +namespace <%= EntityNamespace %> +{ + /// + /// <%= Entity.Description %> + /// + public partial class <%= Entity.ClassName.ToSafeName() %> : Entity + { + public <%= Entity.ClassName.ToSafeName() %>() + { +<% foreach(var p in Entity.Properties) { + if(p.IsPrimaryKey ==true) continue; + string type = p.SystemType.ToNullableType(p.IsNullable == true); + if(type =="int" || type=="decimal") + Response.WriteLine(" this."+p.PropertyName.ToSafeName()+"= 0;"); + else if(type =="string") + Response.WriteLine(" this."+p.PropertyName.ToSafeName()+"= string.Empty;"); + else if(type.ToLower().Contains("datetime")) + Response.WriteLine(" this."+p.PropertyName.ToSafeName()+"= DateTime.Now;"); + } // foreach %> +<% foreach(var r in Entity.Relationships.Where(e => e.ThisCardinality == Cardinality.Many)) { %> + <%= r.ThisPropertyName.ToSafeName() %> = new List<<%= r.OtherEntity.ToSafeName() %>>(); +<% } // foreach %> + } + +<% foreach(var p in Entity.Properties) { + if(p.IsPrimaryKey ==true) continue; + %> + /// + /// <%=p.Description %> + /// + public <%= p.SystemType.ToNullableType(p.IsNullable == true) %> <%= p.PropertyName.ToSafeName() %> { get; set; } +<% } // foreach %> + +<% foreach(var r in Entity.Relationships) { %> +<% if(r.ThisCardinality == Cardinality.Many) { %> + public virtual ICollection<<%= r.OtherEntity.ToSafeName() %>> <%= r.ThisPropertyName.ToSafeName() %> { get; set; } +<% } else { %> + public virtual <%= r.OtherEntity.ToSafeName() %> <%= r.ThisPropertyName.ToSafeName() %> { get; set; } +<% } %> +<% } // foreach %> + } } \ No newline at end of file diff --git a/CodeSmith/CSharp/Internal/Extensions.cs b/CodeSmith/CSharp/Internal/Extensions.cs index 0e8dc289..41fffbf1 100644 --- a/CodeSmith/CSharp/Internal/Extensions.cs +++ b/CodeSmith/CSharp/Internal/Extensions.cs @@ -1,187 +1,187 @@ -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 _csharpKeywords; - private static readonly HashSet _visualBasicKeywords; - private static readonly Dictionary _csharpTypeAlias; - - static Extensions() - { - _csharpKeywords = new HashSet(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(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(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 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 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(); - } - - } -} +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 _csharpKeywords; + private static readonly HashSet _visualBasicKeywords; + private static readonly Dictionary _csharpTypeAlias; + + static Extensions() + { + _csharpKeywords = new HashSet(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(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(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 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 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(); + } + + } +} diff --git a/CodeSmith/CSharp/Internal/Generator.cs b/CodeSmith/CSharp/Internal/Generator.cs index b5ffa8e4..c3ecd1c6 100644 --- a/CodeSmith/CSharp/Internal/Generator.cs +++ b/CodeSmith/CSharp/Internal/Generator.cs @@ -1,816 +1,816 @@ -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 { @"^\d+" }; - IgnoreExpressions = new List(); - } - - public TableNaming TableNaming { get; set; } - - public EntityNaming EntityNaming { get; set; } - - public RelationshipNaming RelationshipNaming { get; set; } - - public ContextNaming ContextNaming { get; set; } - - public List IgnoreExpressions { get; set; } - - public List 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> _names; - - public UniqueNamer() - { - _names = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); - Comparer = StringComparer.CurrentCulture; - - // add existing - UniqueContextName("ChangeTracker"); - UniqueContextName("Configuration"); - UniqueContextName("Database"); - UniqueContextName("InternalContext"); - } - - public IEqualityComparer Comparer { get; set; } - - public string UniqueName(string bucketName, string name) - { - var hashSet = _names.GetOrAdd(bucketName, k => new HashSet(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 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; } - } - - 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; - } - - - private 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; - } - - /// - /// 创建实体的属性 - /// - 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(foreignMembers); - foreignRelationship.OtherEntity = primaryName; - foreignRelationship.OtherProperties = new List(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(primaryMembers); - primaryRelationship.OtherEntity = foreignName; - primaryRelationship.OtherProperties = new List(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(joinLeftColumn); - left.JoinOtherColumn = new List(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(joinRightColumn); - right.JoinOtherColumn = new List(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(); - - 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 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 GetKeyMembers(Entity entity, IEnumerable members, string name, out bool isRequired) - { - var keyMembers = new List(); - 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 - } -} +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 { @"^\d+" }; + IgnoreExpressions = new List(); + } + + public TableNaming TableNaming { get; set; } + + public EntityNaming EntityNaming { get; set; } + + public RelationshipNaming RelationshipNaming { get; set; } + + public ContextNaming ContextNaming { get; set; } + + public List IgnoreExpressions { get; set; } + + public List 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> _names; + + public UniqueNamer() + { + _names = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); + Comparer = StringComparer.CurrentCulture; + + // add existing + UniqueContextName("ChangeTracker"); + UniqueContextName("Configuration"); + UniqueContextName("Database"); + UniqueContextName("InternalContext"); + } + + public IEqualityComparer Comparer { get; set; } + + public string UniqueName(string bucketName, string name) + { + var hashSet = _names.GetOrAdd(bucketName, k => new HashSet(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 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; } + } + + 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; + } + + + private 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; + } + + /// + /// 创建实体的属性 + /// + 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(foreignMembers); + foreignRelationship.OtherEntity = primaryName; + foreignRelationship.OtherProperties = new List(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(primaryMembers); + primaryRelationship.OtherEntity = foreignName; + primaryRelationship.OtherProperties = new List(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(joinLeftColumn); + left.JoinOtherColumn = new List(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(joinRightColumn); + right.JoinOtherColumn = new List(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(); + + 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 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 GetKeyMembers(Entity entity, IEnumerable members, string name, out bool isRequired) + { + var keyMembers = new List(); + 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 + } +} diff --git a/CodeSmith/CSharp/Internal/Mapping.Generated.cst b/CodeSmith/CSharp/Internal/Mapping.Generated.cst index ed4136fd..8d59b7fd 100644 --- a/CodeSmith/CSharp/Internal/Mapping.Generated.cst +++ b/CodeSmith/CSharp/Internal/Mapping.Generated.cst @@ -1,294 +1,294 @@ -<%@ Template Language="C#" TargetLanguage="C#" Debug="True" Encoding="UTF-8" %> - -<%@ Assembly Src="Model.cs" %> -<%@ Assembly Src="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="Entity" Type="SchemaMapper.Entity" %> -<%@ Property Name="ContextNamespace" Type="System.String" %> -<%@ Property Name="EntityNamespace" Type="System.String" %> -<%@ Property Name="MappingNamespace" Type="System.String" %> -//------------------------------------------------------------------------------ -// -// 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. -// -//------------------------------------------------------------------------------ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace <%= MappingNamespace %> -{ - public partial class <%= Entity.MappingName.ToSafeName() %> - : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<<%= EntityNamespace %>.<%= Entity.ClassName.ToSafeName() %>> - { - public <%= Entity.MappingName.ToSafeName() %>() - { - // table -<% if (string.IsNullOrEmpty(Entity.TableSchema)) { %> - ToTable("<%= Entity.TableName %>"); -<% } else { %> - ToTable("<%= Entity.TableName %>", "<%= Entity.TableSchema %>"); -<% } %> - - // keys -<% if (Entity.Properties.PrimaryKeys.Count() > 0) { %> - HasKey(t => <%= KeyExpression(Entity.Properties.PrimaryKeys, "t") %>); -<% } %> - - // Properties -<% -foreach(var p in Entity.Properties) -{ - Response.Write(PropertyExpression(p)); -} -%> - - // Relationships -<% -foreach(var r in Entity.Relationships.Where(e => e.IsMapped)) -{ - if (r.IsManyToMany) - Response.Write(ManyToManyExpression(r)); - else - Response.Write(RelationshipExpression(r)); -} -%> - } - } -} - - \ No newline at end of file diff --git a/CodeSmith/CSharp/Internal/Model.cs b/CodeSmith/CSharp/Internal/Model.cs index b7b2a6f1..f8d51e06 100644 --- a/CodeSmith/CSharp/Internal/Model.cs +++ b/CodeSmith/CSharp/Internal/Model.cs @@ -1,370 +1,370 @@ -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(); - ThisProperties = new List(); - } - - public string RelationshipName { get; set; } - - public string ThisEntity { get; set; } - public string ThisPropertyName { get; set; } - public Cardinality ThisCardinality { get; set; } - public List ThisProperties { get; set; } - - public string OtherEntity { get; set; } - public string OtherPropertyName { get; set; } - public Cardinality OtherCardinality { get; set; } - public List 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 JoinThisColumn { get; set; } - public List JoinOtherColumn { get; set; } - - } - - [DebuggerDisplay("Suffix: {NameSuffix}, IsKey: {IsKey}, IsUnique: {IsUnique}")] - public class Method : EntityBase - { - public Method() - { - Properties = new List(); - } - - 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 Properties { get; set; } - } - #endregion - - #region Collections - public class EntityCollection - : ObservableCollection - { - 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 - { - public bool IsProcessed { get; set; } - - public IEnumerable PrimaryKeys - { - get { return this.Where(p => p.IsPrimaryKey == true); } - } - - public IEnumerable 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 - { - 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 - { - public bool IsProcessed { get; set; } - } - - #endregion -} - +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(); + ThisProperties = new List(); + } + + public string RelationshipName { get; set; } + + public string ThisEntity { get; set; } + public string ThisPropertyName { get; set; } + public Cardinality ThisCardinality { get; set; } + public List ThisProperties { get; set; } + + public string OtherEntity { get; set; } + public string OtherPropertyName { get; set; } + public Cardinality OtherCardinality { get; set; } + public List 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 JoinThisColumn { get; set; } + public List JoinOtherColumn { get; set; } + + } + + [DebuggerDisplay("Suffix: {NameSuffix}, IsKey: {IsKey}, IsUnique: {IsUnique}")] + public class Method : EntityBase + { + public Method() + { + Properties = new List(); + } + + 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 Properties { get; set; } + } + #endregion + + #region Collections + public class EntityCollection + : ObservableCollection + { + 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 + { + public bool IsProcessed { get; set; } + + public IEnumerable PrimaryKeys + { + get { return this.Where(p => p.IsPrimaryKey == true); } + } + + public IEnumerable 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 + { + 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 + { + public bool IsProcessed { get; set; } + } + + #endregion +} + diff --git a/CodeSmith/CSharp/Internal/Parser.cs b/CodeSmith/CSharp/Internal/Parser.cs index 95766be9..fcc8ae56 100644 --- a/CodeSmith/CSharp/Internal/Parser.cs +++ b/CodeSmith/CSharp/Internal/Parser.cs @@ -1,639 +1,639 @@ -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(); - Relationships = new List(); - } - - public string EntityClass { get; set; } - public string MappingClass { get; set; } - - public string TableName { get; set; } - public string TableSchema { get; set; } - - public List Properties { get; private set; } - public List 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(); - JoinThisColumn = new List(); - JoinOtherColumn = new List(); - } - - public string ThisPropertyName { get; set; } - public List ThisProperties { get; private set; } - - public string OtherPropertyName { get; set; } - - public string JoinTable { get; set; } - public string JoinSchema { get; set; } - public List JoinThisColumn { get; private set; } - public List JoinOtherColumn { get; private set; } - } - - public class MappingVisitor : DepthFirstAstVisitor - { - 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().FirstOrDefault(); - if (baseType == null || baseType.MemberName != MappingBaseType) - return base.VisitTypeDeclaration(typeDeclaration, data); - - var entity = baseType.TypeArguments.OfType().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().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() - .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() - .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() - .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() - .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() - .Select(m => m.MemberName); - - foreignRelation.ThisProperties.AddRange(properties); - - return base.VisitInvocationExpression(invocationExpression, foreignRelation); - } - break; - case "HasMany": - var hasManyExpression = invocationExpression.Arguments - .OfType() - .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() - .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() - .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() - .Select(e => e.Value.ToString()); - - parsedRelationship.JoinThisColumn.AddRange(leftKeyExpression); - break; - case "MapRightKey": - if (parsedRelationship == null) - break; - - var rightKeyExpression = invocationExpression.Arguments - .OfType() - .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(); - } - - public string ContextClass { get; set; } - - public List 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 - { - 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() - .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() - .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>(); - - // 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); - 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; - } - } - } -} +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(); + Relationships = new List(); + } + + public string EntityClass { get; set; } + public string MappingClass { get; set; } + + public string TableName { get; set; } + public string TableSchema { get; set; } + + public List Properties { get; private set; } + public List 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(); + JoinThisColumn = new List(); + JoinOtherColumn = new List(); + } + + public string ThisPropertyName { get; set; } + public List ThisProperties { get; private set; } + + public string OtherPropertyName { get; set; } + + public string JoinTable { get; set; } + public string JoinSchema { get; set; } + public List JoinThisColumn { get; private set; } + public List JoinOtherColumn { get; private set; } + } + + public class MappingVisitor : DepthFirstAstVisitor + { + 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().FirstOrDefault(); + if (baseType == null || baseType.MemberName != MappingBaseType) + return base.VisitTypeDeclaration(typeDeclaration, data); + + var entity = baseType.TypeArguments.OfType().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().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() + .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() + .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() + .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() + .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() + .Select(m => m.MemberName); + + foreignRelation.ThisProperties.AddRange(properties); + + return base.VisitInvocationExpression(invocationExpression, foreignRelation); + } + break; + case "HasMany": + var hasManyExpression = invocationExpression.Arguments + .OfType() + .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() + .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() + .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() + .Select(e => e.Value.ToString()); + + parsedRelationship.JoinThisColumn.AddRange(leftKeyExpression); + break; + case "MapRightKey": + if (parsedRelationship == null) + break; + + var rightKeyExpression = invocationExpression.Arguments + .OfType() + .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(); + } + + public string ContextClass { get; set; } + + public List 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 + { + 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() + .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() + .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>(); + + // 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); + 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; + } + } + } +} diff --git a/CodeSmith/CSharp/Web/Application.cst b/CodeSmith/CSharp/Web/Application.cst index 8425cd7b..dbfea3a5 100644 --- a/CodeSmith/CSharp/Web/Application.cst +++ b/CodeSmith/CSharp/Web/Application.cst @@ -1,138 +1,138 @@ -<%-- -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="模块名称" %> -<%@ Property Name="NeedViewModel" Type="Boolean" Category="Context" Default="False" Description="是否需要ViewModel" %> -<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %> -<%@ Assembly Name="SchemaExplorer" %> -<%@ Import Namespace="SchemaExplorer" %> - - -<%if(NeedViewModel){ %> -using OpenAuth.App.ViewModel; -<%} %> -using OpenAuth.Domain; -using OpenAuth.Domain.Interface; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenAuth.App -{ - public class <%=ModuleName%>ManagerApp - { - private I<%=ModuleName%>Repository _repository; - private IOrgRepository _orgRepository; - - public <%=ModuleName%>ManagerApp(I<%=ModuleName%>Repository repository, - IOrgRepository orgRepository) - { - _repository = repository; - _orgRepository = orgRepository; - } - - public int Get<%=GetModelName()%>CntInOrg(int orgId) - { - if (orgId == 0) - { - return _repository.Find(null).Count(); - } - else - { - return _repository.Get<%=GetModelName()%>CntInOrgs(GetSubOrgIds(orgId)); - } - } - - public List<<%=GetModelName()%>> LoadAll() - { - return _repository.Find(null).ToList(); - } - - /// - /// 加载一个节点下面的一个或全部<%=GetModelName()%>s - /// - public dynamic Load(int orgId, int pageindex, int pagesize) - { - IEnumerable<<%=ModuleName%>> <%=ModuleName%>s; - int total = 0; - if (orgId == 0) - { - <%=ModuleName%>s = _repository.Load<%=ModuleName%>s(pageindex, pagesize); - total = _repository.GetCount(); - } - else - { - <%=ModuleName%>s = _repository.LoadInOrgs(pageindex, pagesize,GetSubOrgIds(orgId)); - total = _repository.Get<%=ModuleName%>CntInOrgs(orgId); - } - <%if(NeedViewModel){ %> - var <%=ModuleName%>views = new List<<%=ModuleName%>View>(); - foreach (var <%=ModuleName%> in <%=ModuleName%>s) - { - <%=ModuleName%>View uv = <%=ModuleName%>; - uv.Organizations = string.Join(",", _orgRepository.LoadBy<%=ModuleName%>(<%=ModuleName%>.Id).Select(u => u.Name).ToList()); - <%=ModuleName%>views.Add(uv); - } - <%} %> - - return new - { - total = total, - list = <%=GetModelName()%>s, - pageCurrent = pageindex - }; - } - - /// - /// 获取当前节点的所有下级节点 - /// - private int[] GetSubOrgIds(int orgId) - { - var org = _orgRepository.FindSingle(u => u.Id == orgId); - var orgs = _orgRepository.Find(u => u.CascadeId.Contains(org.CascadeId)).Select(u => u.Id).ToArray(); - return orgs; - } - - public <%=GetModelName()%> Find(int id) - { - var <%=ModuleName.ToLower()%> = _repository.FindSingle(u => u.Id == id); - if (<%=ModuleName.ToLower()%> == null) return new <%=GetModelName()%>(); - - return <%=ModuleName.ToLower() %>; - } - - public void Delete(int id) - { - _repository.Delete(id); - } - - public void AddOrUpdate(<%=GetModelName()%> model) - { - <%=ModuleName%> <%=ModuleName.ToLower()%> = new <%=ModuleName%>(); - model.CopyTo(<%=ModuleName.ToLower()%>); - - if (<%=ModuleName.ToLower()%>.Id == 0) - { - _repository.Add(<%=ModuleName.ToLower()%>); - } - else - { - _repository.Update(<%=ModuleName.ToLower()%>); - } - - } - - - } +<%-- +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="模块名称" %> +<%@ Property Name="NeedViewModel" Type="Boolean" Category="Context" Default="False" Description="是否需要ViewModel" %> +<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %> +<%@ Assembly Name="SchemaExplorer" %> +<%@ Import Namespace="SchemaExplorer" %> + + +<%if(NeedViewModel){ %> +using OpenAuth.App.ViewModel; +<%} %> +using OpenAuth.Domain; +using OpenAuth.Domain.Interface; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenAuth.App +{ + public class <%=ModuleName%>ManagerApp + { + private I<%=ModuleName%>Repository _repository; + private IOrgRepository _orgRepository; + + public <%=ModuleName%>ManagerApp(I<%=ModuleName%>Repository repository, + IOrgRepository orgRepository) + { + _repository = repository; + _orgRepository = orgRepository; + } + + public int Get<%=GetModelName()%>CntInOrg(int orgId) + { + if (orgId == 0) + { + return _repository.Find(null).Count(); + } + else + { + return _repository.Get<%=GetModelName()%>CntInOrgs(GetSubOrgIds(orgId)); + } + } + + public List<<%=GetModelName()%>> LoadAll() + { + return _repository.Find(null).ToList(); + } + + /// + /// 加载一个节点下面的一个或全部<%=GetModelName()%>s + /// + public dynamic Load(int orgId, int pageindex, int pagesize) + { + IEnumerable<<%=ModuleName%>> <%=ModuleName%>s; + int total = 0; + if (orgId == 0) + { + <%=ModuleName%>s = _repository.Load<%=ModuleName%>s(pageindex, pagesize); + total = _repository.GetCount(); + } + else + { + <%=ModuleName%>s = _repository.LoadInOrgs(pageindex, pagesize,GetSubOrgIds(orgId)); + total = _repository.Get<%=ModuleName%>CntInOrgs(orgId); + } + <%if(NeedViewModel){ %> + var <%=ModuleName%>views = new List<<%=ModuleName%>View>(); + foreach (var <%=ModuleName%> in <%=ModuleName%>s) + { + <%=ModuleName%>View uv = <%=ModuleName%>; + uv.Organizations = string.Join(",", _orgRepository.LoadBy<%=ModuleName%>(<%=ModuleName%>.Id).Select(u => u.Name).ToList()); + <%=ModuleName%>views.Add(uv); + } + <%} %> + + return new + { + total = total, + list = <%=GetModelName()%>s, + pageCurrent = pageindex + }; + } + + /// + /// 获取当前节点的所有下级节点 + /// + private int[] GetSubOrgIds(int orgId) + { + var org = _orgRepository.FindSingle(u => u.Id == orgId); + var orgs = _orgRepository.Find(u => u.CascadeId.Contains(org.CascadeId)).Select(u => u.Id).ToArray(); + return orgs; + } + + public <%=GetModelName()%> Find(int id) + { + var <%=ModuleName.ToLower()%> = _repository.FindSingle(u => u.Id == id); + if (<%=ModuleName.ToLower()%> == null) return new <%=GetModelName()%>(); + + return <%=ModuleName.ToLower() %>; + } + + public void Delete(int id) + { + _repository.Delete(id); + } + + public void AddOrUpdate(<%=GetModelName()%> model) + { + <%=ModuleName%> <%=ModuleName.ToLower()%> = new <%=ModuleName%>(); + model.CopyTo(<%=ModuleName.ToLower()%>); + + if (<%=ModuleName.ToLower()%>.Id == 0) + { + _repository.Add(<%=ModuleName.ToLower()%>); + } + else + { + _repository.Update(<%=ModuleName.ToLower()%>); + } + + } + + + } } \ No newline at end of file diff --git a/CodeSmith/CSharp/Web/Controller.cst b/CodeSmith/CSharp/Web/Controller.cst index c4352691..ce38c749 100644 --- a/CodeSmith/CSharp/Web/Controller.cst +++ b/CodeSmith/CSharp/Web/Controller.cst @@ -1,110 +1,110 @@ -<%-- -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="模块名称" %> -<%@ Property Name="NeedViewModel" Type="Boolean" Category="Context" Default="False" Description="是否需要ViewModel" %> -<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %> -<%@ Assembly Name="SchemaExplorer" %> -<%@ Import Namespace="SchemaExplorer" %> - - -using System; -using System.Web.Mvc; -using Infrastructure; -using OpenAuth.App; -<%if(NeedViewModel){ %> -using OpenAuth.App.ViewModel; -<%} %> -using OpenAuth.Domain; - -namespace OpenAuth.Mvc.Controllers -{ - public class <%=ModuleName%>ManagerController : BaseController - { - private <%=ModuleName%>ManagerApp _app; - - public <%=ModuleName%>ManagerController() - { - _app = AutofacExt.GetFromFac<<%=ModuleName%>ManagerApp>(); - } - - // - // GET: /UserManager/ - public ActionResult Index() - { - return View(); - } - - public ActionResult Add(int id = 0) - { - return View(_app.Find(id)); - } - - //添加或修改<%=ModuleName %> - [HttpPost] - public string Add(<%=GetModelName()%> model) - { - try - { - _app.AddOrUpdate(model); - - } - catch (Exception ex) - { - BjuiResponse.statusCode = "300"; - BjuiResponse.message = ex.Message; - } - return JsonHelper.Instance.Serialize(BjuiResponse); - } - - /// - /// 加载节点下面的所有<%=ModuleName %>s - /// - public string Load(int parentId, int pageCurrent = 1, int pageSize = 30) - { - return JsonHelper.Instance.Serialize(_app.Load(parentId, pageCurrent, pageSize)); - } - - public string LoadForTree() - { - var models = _app.LoadAll(); - //添加根节点 - models.Add(new <%=ModuleName %> - { - Id = 0, - ParentId = -1, - Name = "根结点", - CascadeId = "0" - }); - return JsonHelper.Instance.Serialize(models); - } - - public string Delete(int Id) - { - try - { - _app.Delete(Id); - } - catch (Exception e) - { - BjuiResponse.statusCode = "300"; - BjuiResponse.message = e.Message; - } - - return JsonHelper.Instance.Serialize(BjuiResponse); - } - - - } +<%-- +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="模块名称" %> +<%@ Property Name="NeedViewModel" Type="Boolean" Category="Context" Default="False" Description="是否需要ViewModel" %> +<%@ Map Name="CSharpAlias" Src="System-CSharpAlias" Description="System to C# Type Map" %> +<%@ Assembly Name="SchemaExplorer" %> +<%@ Import Namespace="SchemaExplorer" %> + + +using System; +using System.Web.Mvc; +using Infrastructure; +using OpenAuth.App; +<%if(NeedViewModel){ %> +using OpenAuth.App.ViewModel; +<%} %> +using OpenAuth.Domain; + +namespace OpenAuth.Mvc.Controllers +{ + public class <%=ModuleName%>ManagerController : BaseController + { + private <%=ModuleName%>ManagerApp _app; + + public <%=ModuleName%>ManagerController() + { + _app = AutofacExt.GetFromFac<<%=ModuleName%>ManagerApp>(); + } + + // + // GET: /UserManager/ + public ActionResult Index() + { + return View(); + } + + public ActionResult Add(int id = 0) + { + return View(_app.Find(id)); + } + + //添加或修改<%=ModuleName %> + [HttpPost] + public string Add(<%=GetModelName()%> model) + { + try + { + _app.AddOrUpdate(model); + + } + catch (Exception ex) + { + BjuiResponse.statusCode = "300"; + BjuiResponse.message = ex.Message; + } + return JsonHelper.Instance.Serialize(BjuiResponse); + } + + /// + /// 加载节点下面的所有<%=ModuleName %>s + /// + public string Load(int parentId, int pageCurrent = 1, int pageSize = 30) + { + return JsonHelper.Instance.Serialize(_app.Load(parentId, pageCurrent, pageSize)); + } + + public string LoadForTree() + { + var models = _app.LoadAll(); + //添加根节点 + models.Add(new <%=ModuleName %> + { + Id = 0, + ParentId = -1, + Name = "根结点", + CascadeId = "0" + }); + return JsonHelper.Instance.Serialize(models); + } + + public string Delete(int Id) + { + try + { + _app.Delete(Id); + } + catch (Exception e) + { + BjuiResponse.statusCode = "300"; + BjuiResponse.message = e.Message; + } + + return JsonHelper.Instance.Serialize(BjuiResponse); + } + + + } } \ No newline at end of file diff --git a/CodeSmith/CSharp/Web/Index.cshtml.cst b/CodeSmith/CSharp/Web/Index.cshtml.cst index 4705c8e6..8b7fc5b6 100644 --- a/CodeSmith/CSharp/Web/Index.cshtml.cst +++ b/CodeSmith/CSharp/Web/Index.cshtml.cst @@ -1,105 +1,105 @@ -<%-- -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 -{ - -} - - -
-
    - - - - - <% foreach (ColumnSchema column in this.SourceTable.Columns) {%> - - <% }%> - - - -
    <%=Tools.GetDescription(column)%>
    -
    - - - - - - - - - +<%-- +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 +{ + +} + + +
    +
      + + + + + <% foreach (ColumnSchema column in this.SourceTable.Columns) {%> + + <% }%> + + + +
      <%=Tools.GetDescription(column)%>
      +
      + + + + + + + + + diff --git a/CodeSmith/CSharp/Web/Util.cs b/CodeSmith/CSharp/Web/Util.cs index 0ebb0882..9134997d 100644 --- a/CodeSmith/CSharp/Web/Util.cs +++ b/CodeSmith/CSharp/Web/Util.cs @@ -1,24 +1,24 @@ -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") ; - } - } +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") ; + } + } } \ No newline at end of file diff --git a/CodeSmith/CSharp/Web/index.js.cst b/CodeSmith/CSharp/Web/index.js.cst index 72e8807a..c71aa831 100644 --- a/CodeSmith/CSharp/Web/index.js.cst +++ b/CodeSmith/CSharp/Web/index.js.cst @@ -1,166 +1,166 @@ -<%-- -Name: 主JS界面 -Author: yubaolee ---%> -<%@ CodeTemplate Language="C#" TargetLanguage="C#" Debug="False" Encoding="utf-8" 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" %> - -layui.config({ - base: "/js/" -}).use(['form','vue', 'ztree', 'layer', 'jquery', 'table','droptree','openauth'], function () { - var form = layui.form, - //layer = (parent == undefined || parent.layer === undefined )? layui.layer : parent.layer, - layer = layui.layer, - $ = layui.jquery; - var table = layui.table; - var openauth = layui.openauth; - layui.droptree("/UserSession/GetOrgs", "#Organizations", "#OrganizationIds"); - - //主列表加载,可反复调用进行刷新 - var config= {}; //table的参数,如搜索key,点击tree的id - var mainList = function (options) { - if (options != undefined) { - $.extend(config, options); - } - table.reload('mainList', { - url: '/<%=ModuleName%>Manager/Load', - where: config - }); - } - //左边树状机构列表 - var ztree = function () { - var url = '/UserSession/GetOrgs'; - var zTreeObj; - var setting = { - view: { selectedMulti: false }, - data: { - key: { - name: 'Name', - title: 'Name' - }, - simpleData: { - enable: true, - idKey: 'Id', - pIdKey: 'ParentId', - rootPId: 'null' - } - }, - callback: { - onClick: function (event, treeId, treeNode) { - mainList({ orgId: treeNode.Id }); - } - } - }; - var load = function () { - $.getJSON(url, function (json) { - zTreeObj = $.fn.zTree.init($("#tree"), setting, json); - mainList({ orgId: json[0].Id }); - zTreeObj.expandAll(true); - }); - }; - load(); - return { - reload: load - } - }(); - - //添加(编辑)对话框 - var editDlg = function() { - var vm = new Vue({ - el: "#formEdit" - }); - var update = false; //是否为更新 - var show = function (data) { - var title = update ? "编辑信息" : "添加"; - layer.open({ - title: title, - area: ["500px", "400px"], - type: 1, - content: $('#divEdit'), - success: function() { - vm.$set('$data', data); - }, - end: mainList - }); - var url = "/<%=ModuleName%>Manager/Add"; - if (update) { - url = "/<%=ModuleName%>Manager/Update"; //暂时和添加一个地址 - } - //提交数据 - form.on('submit(formSubmit)', - function(data) { - $.post(url, - data.field, - function(data) { - layer.msg(data.Message); - }, - "json"); - return false; - }); - } - return { - add: function() { //弹出添加 - update = false; - show({ - Id: '' - }); - }, - update: function(data) { //弹出编辑框 - update = true; - show(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%>Manager/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 +<%-- +Name: 主JS界面 +Author: yubaolee +--%> +<%@ CodeTemplate Language="C#" TargetLanguage="C#" Debug="False" Encoding="utf-8" 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" %> + +layui.config({ + base: "/js/" +}).use(['form','vue', 'ztree', 'layer', 'jquery', 'table','droptree','openauth'], function () { + var form = layui.form, + //layer = (parent == undefined || parent.layer === undefined )? layui.layer : parent.layer, + layer = layui.layer, + $ = layui.jquery; + var table = layui.table; + var openauth = layui.openauth; + layui.droptree("/UserSession/GetOrgs", "#Organizations", "#OrganizationIds"); + + //主列表加载,可反复调用进行刷新 + var config= {}; //table的参数,如搜索key,点击tree的id + var mainList = function (options) { + if (options != undefined) { + $.extend(config, options); + } + table.reload('mainList', { + url: '/<%=ModuleName%>Manager/Load', + where: config + }); + } + //左边树状机构列表 + var ztree = function () { + var url = '/UserSession/GetOrgs'; + var zTreeObj; + var setting = { + view: { selectedMulti: false }, + data: { + key: { + name: 'Name', + title: 'Name' + }, + simpleData: { + enable: true, + idKey: 'Id', + pIdKey: 'ParentId', + rootPId: 'null' + } + }, + callback: { + onClick: function (event, treeId, treeNode) { + mainList({ orgId: treeNode.Id }); + } + } + }; + var load = function () { + $.getJSON(url, function (json) { + zTreeObj = $.fn.zTree.init($("#tree"), setting, json); + mainList({ orgId: json[0].Id }); + zTreeObj.expandAll(true); + }); + }; + load(); + return { + reload: load + } + }(); + + //添加(编辑)对话框 + var editDlg = function() { + var vm = new Vue({ + el: "#formEdit" + }); + var update = false; //是否为更新 + var show = function (data) { + var title = update ? "编辑信息" : "添加"; + layer.open({ + title: title, + area: ["500px", "400px"], + type: 1, + content: $('#divEdit'), + success: function() { + vm.$set('$data', data); + }, + end: mainList + }); + var url = "/<%=ModuleName%>Manager/Add"; + if (update) { + url = "/<%=ModuleName%>Manager/Update"; //暂时和添加一个地址 + } + //提交数据 + form.on('submit(formSubmit)', + function(data) { + $.post(url, + data.field, + function(data) { + layer.msg(data.Message); + }, + "json"); + return false; + }); + } + return { + add: function() { //弹出添加 + update = false; + show({ + Id: '' + }); + }, + update: function(data) { //弹出编辑框 + update = true; + show(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%>Manager/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 }) \ No newline at end of file diff --git a/CodeSmith/CSharp/WebGenerate.cst b/CodeSmith/CSharp/WebGenerate.cst index f02fbc9a..0467589b 100644 --- a/CodeSmith/CSharp/WebGenerate.cst +++ b/CodeSmith/CSharp/WebGenerate.cst @@ -1,146 +1,146 @@ -<%@ 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" %> - -<%@ Property Name="NeedViewModel" - Type="Boolean" - Default="False" - Optional="True" - Description="是否需要ViewModel" %> - - -<%@ Register Name="ApplicationGenerateClass" - Template="Web\Application.cst" - MergeProperties="False" %> -<%@ Register Name="HtmlGenerateClass" - Template="Web\Index.cshtml.cst" - MergeProperties="False" %> -<%@ Register Name="JSGenerateClass" - Template="Web\index.js.cst" - MergeProperties="False" %> -Generating Entities ... -<% Generate(); %> - - \ No newline at end of file diff --git a/OpenAuth.App/AuthoriseService.cs b/OpenAuth.App/AuthoriseService.cs index c3ae0dde..62d501fc 100644 --- a/OpenAuth.App/AuthoriseService.cs +++ b/OpenAuth.App/AuthoriseService.cs @@ -13,7 +13,6 @@ using System; using System.Collections.Generic; using System.Linq; using OpenAuth.Domain; -using OpenAuth.Domain.Interface; namespace OpenAuth.App { @@ -21,9 +20,9 @@ namespace OpenAuth.App /// 领域服务 /// 用户授权服务 /// - public class AuthoriseService + public class AuthoriseService :BaseApp { - public IUnitWork _unitWork { get; set; } + protected User _user; private List _userRoleIds; //用户角色GUID @@ -59,13 +58,13 @@ namespace OpenAuth.App set { _user = value; - _userRoleIds = _unitWork.Find(u => u.FirstId == _user.Id && u.Key == "UserRole").Select(u => u.SecondId).ToList(); + _userRoleIds = UnitWork.Find(u => u.FirstId == _user.Id && u.Key == "UserRole").Select(u => u.SecondId).ToList(); } } public void Check(string userName, string password) { - var _user = _unitWork.FindSingle(u => u.Account == userName); + var _user = Repository.FindSingle(u => u.Account == userName); if (_user == null) { throw new Exception("用户帐号不存在"); @@ -79,11 +78,11 @@ namespace OpenAuth.App /// IQueryable<Org>. public virtual IQueryable GetOrgsQuery() { - var orgids = _unitWork.Find( + var orgids = UnitWork.Find( u => (u.FirstId == _user.Id && u.Key == "UserOrg") || (u.Key == "RoleOrg" && _userRoleIds.Contains(u.FirstId))).Select(u => u.SecondId); - return _unitWork.Find(u => orgids.Contains(u.Id)); + return UnitWork.Find(u => orgids.Contains(u.Id)); } /// @@ -92,11 +91,11 @@ namespace OpenAuth.App /// IQueryable<Resource>. public virtual IQueryable GetResourcesQuery() { - var resourceIds = _unitWork.Find( + var resourceIds = UnitWork.Find( u => (u.FirstId == _user.Id && u.Key == "UserResource") || (u.Key == "RoleResource" && _userRoleIds.Contains(u.FirstId))).Select(u => u.SecondId); - return _unitWork.Find(u => resourceIds.Contains(u.Id)); + return UnitWork.Find(u => resourceIds.Contains(u.Id)); } /// @@ -104,11 +103,11 @@ namespace OpenAuth.App /// public virtual IQueryable GetModuleElementsQuery() { - var elementIds = _unitWork.Find( + var elementIds = UnitWork.Find( u => (u.FirstId == _user.Id && u.Key == "UserElement") || (u.Key == "RoleElement" && _userRoleIds.Contains(u.FirstId))).Select(u => u.SecondId); - return _unitWork.Find(u => elementIds.Contains(u.Id)); + return UnitWork.Find(u => elementIds.Contains(u.Id)); } /// @@ -116,17 +115,17 @@ namespace OpenAuth.App /// public virtual IQueryable GetModulesQuery() { - var moduleIds = _unitWork.Find( + var moduleIds = UnitWork.Find( u => (u.FirstId == _user.Id && u.Key == "UserModule") || (u.Key == "RoleModule" && _userRoleIds.Contains(u.FirstId))).Select(u => u.SecondId); - return _unitWork.Find(u => moduleIds.Contains(u.Id)).OrderBy(u => u.SortNo); + return UnitWork.Find(u => moduleIds.Contains(u.Id)).OrderBy(u => u.SortNo); } //用户角色 public virtual IQueryable GetRolesQuery() { - return _unitWork.Find(u => _userRoleIds.Contains(u.Id)); + return UnitWork.Find(u => _userRoleIds.Contains(u.Id)); } } } \ No newline at end of file diff --git a/OpenAuth.App/BaseApp.cs b/OpenAuth.App/BaseApp.cs new file mode 100644 index 00000000..89933024 --- /dev/null +++ b/OpenAuth.App/BaseApp.cs @@ -0,0 +1,24 @@ +using OpenAuth.Domain; +using OpenAuth.Domain.Interface; + +namespace OpenAuth.App +{ + /// + /// 业务层基类,UnitWork用于事务操作,Repository用于普通的数据库操作 + /// 如用户管理:Class UserManagerApp:BaseApp + /// + /// + public class BaseApp where T:Entity + { + /// + /// 用于事务操作 + /// + /// The unit work. + public IUnitWork UnitWork { get; set; } + /// + /// 用于普通的数据库操作 + /// + /// The repository. + public IRepository Repository { get; set; } + } +} diff --git a/OpenAuth.App/OpenAuth.App.csproj b/OpenAuth.App/OpenAuth.App.csproj index 0c723ad6..0cd328dd 100644 --- a/OpenAuth.App/OpenAuth.App.csproj +++ b/OpenAuth.App/OpenAuth.App.csproj @@ -81,6 +81,7 @@ + diff --git a/OpenAuth.App/RevelanceManagerApp.cs b/OpenAuth.App/RevelanceManagerApp.cs index aab0f212..3759fe31 100644 --- a/OpenAuth.App/RevelanceManagerApp.cs +++ b/OpenAuth.App/RevelanceManagerApp.cs @@ -2,6 +2,7 @@ using OpenAuth.Domain; using OpenAuth.Domain.Interface; using System; +using System.Collections.Generic; using System.Linq; namespace OpenAuth.App @@ -89,5 +90,26 @@ namespace OpenAuth.App }).ToArray()); _unitWork.Save(); } + + /// + /// 根据关联表的一个键获取另外键的值 + /// + /// 映射标识 + /// 返回的是否为映射表的第二列,如果不是则返回第一列 + /// 已知的ID列表 + /// List<System.String>. + public List Get(string key, bool returnSecondIds, params string[] ids) + { + if (returnSecondIds) + { + return _unitWork.Find(u => u.Key == key + && ids.Contains(u.FirstId)).Select(u => u.SecondId).ToList(); + } + else + { + return _unitWork.Find(u => u.Key == key + && ids.Contains(u.SecondId)).Select(u => u.FirstId).ToList(); + } + } } } \ No newline at end of file diff --git a/OpenAuth.App/SystemAuthService.cs b/OpenAuth.App/SystemAuthService.cs index d86b4fca..a4b6e26c 100644 --- a/OpenAuth.App/SystemAuthService.cs +++ b/OpenAuth.App/SystemAuthService.cs @@ -29,28 +29,28 @@ namespace OpenAuth.App public override IQueryable GetOrgsQuery() { - return _unitWork.Find(null); + return UnitWork.Find(null); } public override IQueryable GetResourcesQuery() { - return _unitWork.Find(null); + return UnitWork.Find(null); } public override IQueryable GetModuleElementsQuery() { - return _unitWork.Find(null); + return UnitWork.Find(null); } public override IQueryable GetModulesQuery() { - return _unitWork.Find(null); + return UnitWork.Find(null); } public override IQueryable GetRolesQuery() { //用户角色 - return _unitWork.Find(null); + return UnitWork.Find(null); } } } \ No newline at end of file diff --git a/OpenAuth.App/UserManagerApp.cs b/OpenAuth.App/UserManagerApp.cs index 8c0f3fc0..41642f19 100644 --- a/OpenAuth.App/UserManagerApp.cs +++ b/OpenAuth.App/UserManagerApp.cs @@ -1,6 +1,5 @@ using OpenAuth.App.ViewModel; using OpenAuth.Domain; -using OpenAuth.Domain.Interface; using System; using System.Collections.Generic; using System.Linq; @@ -9,15 +8,14 @@ using OpenAuth.App.Request; namespace OpenAuth.App { - public class UserManagerApp + public class UserManagerApp :BaseApp { - public IUnitWork _unitWork { get; set; } public RevelanceManagerApp ReleManagerApp { get; set; } public User Get(string account) { - return _unitWork.FindSingle(u => u.Account == account); + return Repository.FindSingle(u => u.Account == account); } @@ -26,20 +24,24 @@ namespace OpenAuth.App /// public GridData Load(QueryUserListReq request) { - if (request.page < 1) request.page = 1; //TODO:如果列表为空新增加一个用户后,前端会传一个0过来,奇怪?? IEnumerable users; int records = 0; - if (request.orgId ==string.Empty) + if (string.IsNullOrEmpty(request.orgId)) { - users = _unitWork.Find(null).OrderBy(u => u.Id).Skip((request.page - 1) * request.limit).Take(request.limit); - records = _unitWork.GetCount(); + users = UnitWork.Find(null).OrderBy(u => u.Id).Skip((request.page - 1) * request.limit).Take(request.limit); + records = UnitWork.GetCount(); } else { var ids = GetSubOrgIds(request.orgId); - users = _unitWork.Find(u =>ids.Contains(u.Id)).OrderBy(u => u.Id).Skip((request.page - 1) * request.limit).Take(request.limit); - records = _unitWork.GetCount(); + List userIds = ReleManagerApp.Get("UserOrg", false, ids); + users = UnitWork.Find(u =>userIds.Contains(u.Id)) + .OrderBy(u => u.Name) + .Skip((request.page - 1) * request.limit) + .Take(request.limit); + records = UnitWork.GetCount(); } + var userviews = new List(); foreach (var user in users) { @@ -62,14 +64,15 @@ namespace OpenAuth.App /// private string[] GetSubOrgIds(string orgId) { - var org = _unitWork.FindSingle(u => u.Id == orgId); - var orgs = _unitWork.Find(u => u.CascadeId.Contains(org.CascadeId)).Select(u => u.Id).ToArray(); + var org = UnitWork.FindSingle(u => u.Id == orgId); + var orgs = UnitWork.Find(u => u.CascadeId.Contains(org.CascadeId)) + .Select(u => u.Id).ToArray(); return orgs; } public UserView Find(string id) { - var user = _unitWork.FindSingle(u => u.Id == id); + var user = Repository.FindSingle(u => u.Id == id); if (user == null) return new UserView(); UserView view = user; @@ -85,7 +88,7 @@ namespace OpenAuth.App public void Delete(string[] ids) { - _unitWork.Delete(u => ids.Contains(u.Id)); + Repository.Delete(u => ids.Contains(u.Id)); } public void AddOrUpdate(UserView view) @@ -95,19 +98,18 @@ namespace OpenAuth.App User user = view; if (string.IsNullOrEmpty(view.Id)) { - if (_unitWork.IsExist(u => u.Account == view.Account)) + if (UnitWork.IsExist(u => u.Account == view.Account)) { throw new Exception("用户账号已存在"); } user.CreateTime = DateTime.Now; user.Password = user.Account; //初始密码与账号相同 - _unitWork.Add(user); - _unitWork.Save(); + Repository.Add(user); view.Id = user.Id; //要把保存后的ID存入view } else { - _unitWork.Update(u => u.Id == view.Id, u => new User + UnitWork.Update(u => u.Id == view.Id, u => new User { Account = user.Account, BizCode = user.BizCode, @@ -128,8 +130,8 @@ namespace OpenAuth.App /// public IEnumerable LoadByUser(string userId) { - var result = from userorg in _unitWork.Find(null) - join org in _unitWork.Find(null) on userorg.SecondId equals org.Id + var result = from userorg in UnitWork.Find(null) + join org in UnitWork.Find(null) on userorg.SecondId equals org.Id where userorg.FirstId == userId && userorg.Key == "UserOrg" select org; return result; diff --git a/OpenAuth.Mvc/Controllers/UserManagerController.cs b/OpenAuth.Mvc/Controllers/UserManagerController.cs index 8b8709d9..45465296 100644 --- a/OpenAuth.Mvc/Controllers/UserManagerController.cs +++ b/OpenAuth.Mvc/Controllers/UserManagerController.cs @@ -29,11 +29,11 @@ namespace OpenAuth.Mvc.Controllers try { App.AddOrUpdate(view); - + } catch (Exception ex) { - Result.Code = 500; + Result.Code = 500; Result.Message = ex.Message; } return JsonHelper.Instance.Serialize(Result); @@ -56,7 +56,7 @@ namespace OpenAuth.Mvc.Controllers } catch (Exception e) { - Result.Code = 500; + Result.Code = 500; Result.Message = e.Message; } @@ -71,8 +71,8 @@ namespace OpenAuth.Mvc.Controllers /// public string GetAccessedUsers() { - IEnumerable users = App.Load(new QueryUserListReq()).data; - var result = new Dictionary(); + IEnumerable users = App.Load(new QueryUserListReq()).data; + var result = new Dictionary(); foreach (var user in users) { var item = new diff --git a/OpenAuth.UnitTest/TestUser.cs b/OpenAuth.UnitTest/TestUser.cs index 7611ded6..72eb4823 100644 --- a/OpenAuth.UnitTest/TestUser.cs +++ b/OpenAuth.UnitTest/TestUser.cs @@ -48,8 +48,8 @@ namespace OpenAuth.UnitTest { var request = new QueryUserListReq { - orgId = "990cb229-cc18-41f3-8e2b-13f0f0110798", - page = 2, + orgId = "543a9fcf-4770-4fd9-865f-030e562be238", + page = 1, limit = 30 }; var users = _app.Load(request); diff --git a/OpenAuth.WebApi/Areas/SSO/Controllers/CheckController.cs b/OpenAuth.WebApi/Areas/SSO/Controllers/CheckController.cs index 87d688a5..1d271de2 100644 --- a/OpenAuth.WebApi/Areas/SSO/Controllers/CheckController.cs +++ b/OpenAuth.WebApi/Areas/SSO/Controllers/CheckController.cs @@ -27,12 +27,8 @@ namespace OpenAuth.WebApi.Areas.SSO.Controllers /// public class CheckController : ApiController { - private AuthorizeApp _app; + public AuthorizeApp _app { get; set; } private ObjCacheProvider _objCacheProvider = new ObjCacheProvider(); - public CheckController() - { - _app = AutofacExt.GetFromFac(); - } /// /// 检验token是否有效 diff --git a/OpenAuth.WebApi/Areas/SSO/Controllers/LoginController.cs b/OpenAuth.WebApi/Areas/SSO/Controllers/LoginController.cs index 28da832b..67feda0e 100644 --- a/OpenAuth.WebApi/Areas/SSO/Controllers/LoginController.cs +++ b/OpenAuth.WebApi/Areas/SSO/Controllers/LoginController.cs @@ -11,12 +11,7 @@ namespace OpenAuth.WebApi.Areas.SSO.Controllers /// public class LoginController : Controller { - private AppInfoService _appInfoService; - - public LoginController() - { - _appInfoService = new AppInfoService(); - } + public AppInfoService _appInfoService { get; set; } private const string AppInfo = "AppInfo"; diff --git a/OpenAuth.WebApi/AutofacExt.cs b/OpenAuth.WebApi/AutofacExt.cs index c590b825..b6828d38 100644 --- a/OpenAuth.WebApi/AutofacExt.cs +++ b/OpenAuth.WebApi/AutofacExt.cs @@ -13,10 +13,11 @@ // *********************************************************************** using System.Reflection; +using System.Web.Http; using System.Web.Mvc; using Autofac; -using Autofac.Configuration; using Autofac.Integration.Mvc; +using Autofac.Integration.WebApi; using OpenAuth.App; using OpenAuth.Domain.Interface; using OpenAuth.Repository; @@ -50,8 +51,13 @@ namespace OpenAuth.WebApi // OPTIONAL: Enable property injection into action filters. builder.RegisterFilterProvider(); - // Set the dependency resolver to be Autofac. + //注册所有的ApiControllers + builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired(); + var container = builder.Build(); + HttpConfiguration config = GlobalConfiguration.Configuration; + //注册api容器需要使用HttpConfiguration对象 + config.DependencyResolver = new AutofacWebApiDependencyResolver(container); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } diff --git a/OpenAuth.WebApi/OpenAuth.WebApi.csproj b/OpenAuth.WebApi/OpenAuth.WebApi.csproj index 8c031d7c..8b4eecfe 100644 --- a/OpenAuth.WebApi/OpenAuth.WebApi.csproj +++ b/OpenAuth.WebApi/OpenAuth.WebApi.csproj @@ -57,6 +57,10 @@ ..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll True + + ..\packages\Autofac.WebApi2.3.4.0\lib\net45\Autofac.Integration.WebApi.dll + True + ..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll True diff --git a/OpenAuth.WebApi/packages.config b/OpenAuth.WebApi/packages.config index 5ba6f0cb..bd60bdc9 100644 --- a/OpenAuth.WebApi/packages.config +++ b/OpenAuth.WebApi/packages.config @@ -4,6 +4,7 @@ +