自动生成视图模型

时间:2014-01-03 16:40:52

标签: c# asp.net-mvc code-generation visual-studio-2013

我在C#中将Web应用程序从PHP重写为MVC.NET。 通过逆向工程,我生成了EF数据库模型。

由于原始应用程序包含许多表(实体),我想以某种方式从数据库(或来自EF的实体)预生成MVC ViewModel,其属性如

[Required]
[Display(Name = "columnName")]
[StringLength(100)]
...
...

只需通过近似数据库,我就可以编辑一些属性viewmodel,以便在视图中使用。

有没有人做过类似的事情,或者知道VS或插件的任何扩展,工具?

非常感谢

2 个答案:

答案 0 :(得分:1)

执行此操作的“工具”是所谓的t4模板,这是您可以在visual studio中使用的功能,您可以在其中基本生成所需的任何内容。

虽然调试这些模板并不容易,但要小心;)

:编辑:如果您不想自己付出太多精力,可以使用第三方工具构建围绕t4的框架,如http://www.devart.com/entitydeveloper/这是一个很棒的工具,可以生成控制器+视图您的EF或NHibernate模型。或者至少你可以看看模板中的构建并编辑它们......

答案 1 :(得分:0)

我创建了一个visual studio t4模板来做到这一点。它会抓取一个这样的文件:

using MicroMvvm;

namespace MyApplication
{
    [Bindable]
    public partial class MyApplication
    {
        [Bindable] 
        private string _ipAdress;

        [Bindable] 
        private MyChild _child;

        public MyApplication()
        {
            IpAdress = "ip adress test";
            Child = new MyChild(this, "");
        }

        [Bindable]
        void AddDot()
        {
            IpAdress += ".";
        }

        [Can]
        bool CanChangeChild()
        {
            return IpAdress.Trim().Length != 0;
        }

        [Bindable]
        void ChangeChild()
        {
            Child = new MyChild2(this);
        }
    }
}

并生成此文件:

using System;
using System.ComponentModel;
using System.Windows.Input;
using MicroMvvm;

namespace MyApplication
{

    public partial class MyApplication : INotifyPropertyChanged
    {
        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(String propertyName)
        {
            var handler = PropertyChanged;
            if (handler == null) return;
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }

        public String IpAdress
        {
            get { return _ipAdress; }
            set
            {
                _ipAdress = value;
                RaisePropertyChanged("IpAdress");
            }
        }
        public MyChild Child
        {
            get { return _child; }
            set
            {
                _child = value;
                RaisePropertyChanged("Child");
            }
        }
        public ICommand AddDotCommand { get { return new RelayCommand(AddDot, null); } }
        public ICommand ChangeChildCommand { get { return new RelayCommand(ChangeChild, CanChangeChild); } }
    }

}

这是模板,您需要将“MyApplication”更改为包含要转换为视图模型的对象的项目名称。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#@ assembly name="$(SolutionDir)MicroMvvm\bin\Debug\MicroMvvm.dll" #>
<#@ assembly name="$(SolutionDir)MyApplication\bin\Debug\MyApplication.dll" #>
<#@ import namespace="MyApplication" #>
using System;
using System.ComponentModel;
using System.Windows.Input;
using MicroMvvm;

namespace MyApplication
{
<#
    var assembly = typeof(MyApplication).Assembly;

    var types = new HashSet<Type>(assembly.GetTypes().Where(type => Attribute.GetCustomAttribute(type, typeof(MicroMvvm.Bindable)) != null));
    var skip = new HashSet<Type>(types.Where(type => types.Contains(type.BaseType)));

    foreach (Type type in types)
    {
        if (Attribute.GetCustomAttribute(type, typeof(MicroMvvm.Bindable)) == null)
            continue;

#>  
    public partial class <#=type.Name#> <#=skip.Contains(type) ? "" : ": INotifyPropertyChanged"#>
    {
<# 
        if (!skip.Contains(type)) 
        { 
#>
        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(String propertyName)
        {
            var handler = PropertyChanged;
            if (handler == null) return;
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }

<#
        }
        foreach(FieldInfo fieldInfo in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance)) {
            if (!Attribute.IsDefined(fieldInfo, typeof(MicroMvvm.Bindable)))
                continue;
            if (!fieldInfo.Name.StartsWith("_"))
                continue;
            string fieldName = fieldInfo.Name.Substring(1);
            fieldName = char.ToUpper(fieldName[0]) + fieldName.Substring(1);

#>      public <#=fieldInfo.FieldType.Name#> <#=fieldName#>
        {
            get { return <#=fieldInfo.Name#>; }
            set
            {
                <#=fieldInfo.Name#> = value;
                RaisePropertyChanged("<#=fieldName#>");
            }
        }
<#
        }

        foreach(MethodInfo method in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance)) {
            if (!Attribute.IsDefined(method, typeof(MicroMvvm.Bindable)))
                continue;

            MethodInfo canMethod = null;
            foreach(MethodInfo searchMethod in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance)) {
                if (Attribute.IsDefined(searchMethod, typeof(MicroMvvm.Can)) && ("Can" + method.Name).Equals(searchMethod.Name))
                    canMethod = searchMethod;
            }

#>      public ICommand <#=method.Name#>Command { get { return new RelayCommand(<#=method.Name#>, <#= canMethod == null ? "null" : canMethod.Name #>); } }
<#
        }
#>
    }
<#
    }
#>
}

它还需要MicroMvvm框架,以及两个System.Attribute的Bindable和Can。它显着减少了您需要编写的锅炉铭牌代码。但它的边缘有点粗糙。