【问题标题】:Auto generate view model自动生成视图模型
【发布时间】:2014-01-21 09:48:22
【问题描述】:

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

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

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

仅通过近似数据库,因此我可以编辑一些属性视图模型以在视图中使用。

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

非常感谢

【问题讨论】:

  • 我不确定你在追求什么。如果您真的是在生成ViewModels 之后,我会提醒您,您的数据库表和ViewModels 之间的关系非常松散。通常,Views 需要合并来自多个表、cookie、用户输入的数据。这不是通常可以预测的东西,因此是预先生成的。
  • entitydeveloper 可以生成 ViewModel dy dataAnotations?

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


【解决方案1】:

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

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

:edit: 如果你不想自己花太多精力,你可以使用 3rd 方工具,它围绕 t4 构建框架,例如 http://www.devart.com/entitydeveloper/,这是一个很棒的工具,可以从你的EF 或 NHibernate 模型。或者至少您可以查看模板中的构建并对其进行编辑...

【讨论】:

    【解决方案2】:

    我为此创建了一个 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。它显着减少了您需要编写的样板代码。但它的边缘有点粗糙。

    【讨论】:

    • 您好,这很好,但在迭代 EF 对象期间的属性映射并不总是有效
    猜你喜欢
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    相关资源
    最近更新 更多