这是一个基于Razor Engine的代码生成器,在强大的Razor语法支持下通过编写模板针对数据库的Schema或者一段SQL的查询结果生成代码。(模板使用Razor C# 语法)下载地址:http://razorsourcegenerator.codeplex.com/releases/view/96371运行前提:
安装 .net 4.0 client profile特性:
1. 支持多种主流数据库(因为使用OleDb获得Schema,理论上OleDb支持的数据库都可以。)
2. 编写模板比较简单,生成代码非常灵活,并且有一定程度的错误提示(这主要归功于 RazorEngine
    Razor模板内嵌的helper方法,让你编写模板如虎添翼
3. 支持文件名的参数化,可以批量生成代码
4. 可以Append方式生成代码(可将多个Table的信息生成到一个文件中),生成代码更方便
5. 可以通过自定义SQL生成代码[SQLServer mdf file]代码生成 ibatis JAVA 代码示例:
<模板>@* 
  Razor注释:编写Template(BySchema)可以使用下面的变量
  @Model.Context.IsFirst, @Model.Context.IsLast, @Model.TableName, @Model.Columns(多行)
*@
/* FileName:  @ConvNameUpper(Model.TableName)Entity.java
 * (c)Copyright XXX Corporation 2012 All Rights Reserved.
 *
 * History
 * Ver           Author          Date            Comment
 * Ver.1.00      XXX             @DateTime.Now.ToString("yyyy/MM/dd")     Created
 */
package xxx.xxx.xxx.common.entity;import java.math.BigDecimal;
import java.io.Serializable;public final class @ConvNameUpper(Model.TableName)Entity extends BaseEntity {
private static final long serialVersionUID = 1L; @foreach(dynamic x in Model.Columns)
{
  var javaType = GetDbType(x.DataType.ToString(), x.NumericScale.ToString());
  @("    //") @x.Description @("\r\n")
  @("    private ") @javaType @(" ") @ConvNameLower(x.ColumnName) @(";\r\n")
} @foreach(dynamic x in Model.Columns)
{
  var javaType = GetDbType(x.DataType.ToString(), x.NumericScale.ToString());
  @("    /**\r\n") 
  @("     * 「") @x.Description @("」 getter\r\n")
  @("     */\r\n")
  @("    public ") @javaType @(" ") @Getter(x.ColumnName) @("() {\r\n")
  @("        return ") @ConvNameLower(x.ColumnName) @(";\r\n")
  @("    }\r\n")
  @("\r\n")
  @("    /**\r\n") 
  @("     * 「") @x.Description @("」 setter\r\n")
  @("     */\r\n")
  @("    public void ") @Setter(x.ColumnName) @("(") @javaType @(" ") @ConvNameLower(x.ColumnName) @(") {\r\n")
  @("        this.") @ConvNameLower(x.ColumnName) @(" = ") @ConvNameLower(x.ColumnName) @(";\r\n")
  @("    }\r\n")
  @("\r\n")
}
}@helper ConvNameUpper(string str) {
  @string.Join("", str.ToLower().Split('_', ' ').Select(s => char.ToUpper(s[0]).ToString() + s.Substring(1)).ToArray())
}
@helper ConvNameLower(string str) {
  @string.Join("", str.ToLower().Split('_', ' ').Select((s,i) => i==0 ? s : char.ToUpper(s[0]).ToString() + s.Substring(1)).ToArray())
}
@helper Getter(string str) {
  @("get" + string.Join("", str.ToLower().Split('_', ' ').Select(s => char.ToUpper(s[0]).ToString() + s.Substring(1)).ToArray()))
}
@helper Setter(string str) {
  @("set" + string.Join("", str.ToLower().Split('_', ' ').Select(s => char.ToUpper(s[0]).ToString() + s.Substring(1)).ToArray()))
}
@helper Upper(string str) {
  @string.Format("{0}{1}", char.ToUpper(str[0]), str.Substring(1))
}
@helper GetDbType(string type, string scale) {
  @if(type == "System.Decimal" && scale == "0") {
 @("Integer")
  } else if (type == "System.Decimal" && scale != "0") {
 @("BigDecimal")
  } else {
 @("String")
  }
}
通过自定义模板,可以适应不同项目的要求(比如:代码的头部声明,不同项目的命名规则,基类等等)
利用OleDb还可以直接连接 Excel 来生成代码。使用上,比 MyGeneration 要简单得多。
接下来还会实现Razor语法着色,预览等功能,有兴趣的童鞋可以关注这个项目。

解决方案 »

  1.   

    沙发自己做,WPF MVVM 开发效率高啊,感觉要比 winform 快多了。
      

  2.   

    正在用WPF MVVM写一工具自己用
    感觉还不错啊
      

  3.   

    正在摸索中,楼主,是否可以请教请教[email protected]
      

  4.   

    说实在的,代码生成器的技术含量是最低的,其原理就是字符串拼接,如果做出通用型的,那么势必要涉及到很多配置处理,用起来很麻烦,个人建议把所有配置省略,写属于自己的代码生成器,打开就能用,那才能提高效率。
    WPF 我一直看好它的,虽然有人总说它BUG多而不喜。不过WPF的学习难度也不小,本以为很容易上手的,但是思路一改常态,等理解了依赖属性后,估计就可以顺手了。
      

  5.   


    难点在解析引擎,其实Razor 是Asp.net mvc 里开源的解析引擎。
      

  6.   

    顶一下楼主。我也做代码生成器,不过我的实现方案是自己解析模板,没有界面,在VS编译事件中执行。我的C#模板是可编译的C#程序,支持一定程度的重构。我也贴一段网络函数代理C#模板代码        public partial class @serverType : showjim.sys.net.tcpServer
            {
                public static readonly bool isTcpClient = !showjim.sys.config.isConfigName(typeof(showjim.config.tcpCall.server), "@serverType");
                public @serverType(showjim.setup.attribute.tcpServer value)
                    : base(new System.Net.IPAddress(BitConverter.GetBytes(showjim.setup.deploy.process.registerIp)), value.port == 0 ? showjim.setup.deploy.process.register(value.register, value.isRegisterOnly) : value.port, value.verifyFileName, value.isCompress, value.isAsynchronous, value.checkKeepAliveSecond, value.checkKeepAliveSkipSecond) { }
                public @serverType() : this(showjim.sys.config.loadConfig("@tcpCallAttribute.register", showjim.config.tcpCall.server.get(showjim.config.tcpCall.server.enumType.@serverType))) { }
                /// <summary>
                /// 设置命令处理委托集合
                /// </summary>
                [showjim.setup.attribute.tcpCall(isIgnore = true)]
                protected override void SetOnCommands()
                {
                    if (IsAsynchronous)
                    {
                        showjim.sys.list<System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.asyncSocket, int>, bool>>> onCommands = new showjim.sys.list<System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.asyncSocket, int>, bool>>>(@methods.Length + 1);
                        onCommands.addUnsafe(new System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.asyncSocket, int>, bool>>(CloseCommandData, new System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.asyncSocket, int>, bool>(Close, false)));
                        byte[] command;
                        #region LOOP methods
                        showjim.sys.array.reverse(command = showjim.sys.String.bytes("@methodFullName"));
                        onCommands.addUnsafe(new System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.asyncSocket, int>, bool>>(command, new System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.asyncSocket, int>, bool>(@methodIndexName, @isParameter)));
                        #endregion LOOP methods
                        OnCommandsAsynchronous = new showjim.sys.staticDictionary<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.asyncSocket, int>, bool>>(onCommands);
                    }
                    else
                    {
                        showjim.sys.list<System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.socket, int>, bool>>> onCommands = new showjim.sys.list<System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.socket, int>, bool>>>(@methods.Length + 1);
                        onCommands.addUnsafe(new System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.socket, int>, bool>>(CloseCommandData, new System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.socket, int>, bool>(Close, false)));
                        byte[] command;
                        #region LOOP methods
                        showjim.sys.array.reverse(command = showjim.sys.String.bytes("@methodFullName"));
                        onCommands.addUnsafe(new System.Collections.Generic.KeyValuePair<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.socket, int>, bool>>(command, new System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.socket, int>, bool>(@methodIndexName, @isParameter)));
                        #endregion LOOP methods
                        OnCommands = new showjim.sys.staticDictionary<showjim.sys.hashBytes, System.Collections.Generic.KeyValuePair<Action<showjim.sys.net.socket, int>, bool>>(onCommands);
                    }
                }
            }与它的数据视图    [showjim.setup.attribute.cSharp]
        partial class tcpCall : tcpServer<showjim.setup.attribute.tcpCall>
        {
            protected override void SetMembers() { }
            public string defaultNamespace;
            public showjim.config.tcpCall.server.enumType serverType;
            public bool isClass;
            public void create(Type type, showjim.setup.coder.methodInfo[] methods, string defaultNamespace
                , showjim.config.tcpCall.server.enumType serverType)
            {
                this.methods = methods;
                this.defaultNamespace = defaultNamespace;
                this.serverType = serverType;
                isClass = true;
                create(type, (showjim.setup.attribute.tcpCall)null);
            }        public int clientCount
            {
                get { return tcpCallAttribute.clientCount <= 0 ? 1 : tcpCallAttribute.clientCount; }
            }
            public showjim.setup.attribute.tcpServer tcpCallAttribute;
            public string create(showjim.config.tcpCall.server.enumType serverType, showjim.setup.coder.methodInfo[] methods)
            {
                isClass = false;
                tcpCallAttribute = showjim.config.tcpCall.server.get(this.serverType = serverType);
                this.methods = methods;
                Create();
                return Code.ToString();
            }
        }
    代码生成不应该局限于ORM,对于替代反射,函数代理,性能优化方面很有用。
      

  7.   


    嗯,使用Razor的创意非常赞。
      

  8.   

    借个人气
    寻找追求完美的csharper一起搭建一个C#开源框架
      

  9.   

    说实在的,代码生成器的技术含量是最低的,其原理就是字符串拼接,如果做出通用型的,那么势必要涉及到很多配置处理,用起来很麻烦,个人建议把所有配置省略,写属于自己的代码生成器,打开就能用,那才能提高效率。
    WPF 我一直看好它的,虽然有人总说它BUG多而不喜。不过WPF的学习难度也不小,本以为很容易上手的,但是思路一改常态,等理解了依赖属性后,估计就可以顺手了。
      

  10.   

    今天看了一下,语法还是比较简单,但是功能可能简单了些,可能是我不了解的缘故,楼主能否说明一下。
    比如说明有:
    @Model.Context.IsFirst, @Model.Context.IsLast, @Model.TableName, @Model.Columns
    这些变量可用,但是好像少了些,有没有下面字段支持,如没有,能否增加:
    foreach (x in @Model.Columns)
    {
    x.IsFirst ????
    }
      

  11.   

    或者能否详细说明这个Model包含的属性,谢谢
      

  12.   

    为感谢lz,我特增加以下helper函数,用于增加我希望的属性
    @helper PrepareModelColumns() {
    var index = 0;
    foreach(dynamic x in Model.Columns)
    {
    index++;
    x.Index = index;
    x.IsFirst = x.Index == 1;
    x.IsLast = x.Index == Model.Columns.Count;
    }
    }
      

  13.   


    多谢关注,Model.Columns 就是字段的集合了,帮助文档会进一步完善。
    目前可以点击 TableName 的 LinkButton 看到DB的Schema,里面的列就是这个 Columns 里元素的属性。
    foeach(var x in @Model.Columns)
    {
       @x.ColumnName
       @x.ColumnSize
       @x.ColumnOrdinal
       @x.NumericPrecision
       @x.NumericScale
       @x.DataType
       @x.IsLong
       @x.AllowDBNull
       @x.IsReadOnly 
       @x.IsUnique
       @x.IsKey
       @x.IsAutoIncrement
       @x.BaseTableName
       @x.BaseColumnName
       @x.Description
    }
    我会尽快完善文档
      

  14.   

    利用 DTE 自己写一个哈哈,谢谢分享。
      

  15.   

    这是win8的界面吧,挺好看的。我也试用下