سؤال

I am rewriting the web application from PHP to MVC.NET in C#. Through reverse engineering, I generated the EF database model.

Since the original application contains many tables (entities), I want to somehow pregenerate MVC ViewModels from a database (or entities from EF) with attributes such as

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

simply by approximately database so I can edit some attributes viewmodel for use in the view.

Has anyone done something similar, or know of any extension to VS or plug-in, tool ?

Really thanks

هل كانت مفيدة؟

المحلول

The "tool" to do this are the so called t4 templates, which is a feature you can use in visual studio, where you can basically generate whatever you need.

Though it is not that easy to debug those templates, so be careful;)

:edit: If you do not want to put too much effort into it yourself, you can use 3rd party tools which build a framework around t4 like http://www.devart.com/entitydeveloper/ which is a great tool and can generate controllers + views out of your EF or NHibernate model. Or at least you could take a look into the build in templates and edit them...

نصائح أخرى

I created a visual studio t4 template to do just that. It will grab a file like this:

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);
        }
    }
}

And generate this file:

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); } }
    }

}

This is the template, you need to change "MyApplication" to the project name which contains the objects you want to morph into viewmodels.

<#@ 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 #>); } }
<#
        }
#>
    }
<#
    }
#>
}

It also needs the MicroMvvm framework, and two System.Attribute's Bindable and Can. It significantly cuts down on the boiler plate code you need to write. But its a little bit rough around the edges.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top