65.9K
CodeProject 正在变化。 阅读更多。
Home

EntityUI 自动 UI 生成器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.69/5 (15投票s)

2014年3月19日

CPOL

8分钟阅读

viewsIcon

42503

downloadIcon

566

这是“使用 CodeFirst 方法的 EntityUI 自动 UI 生成器”的替代方案。

引言

EntityUI 基本上是一个理念,旨在通过在 ASP.NET 应用程序中使用 Code First 方法自动创建用户界面和数据库存储库,来快速生成您的应用程序。作为开发者,您将编写您的领域模型 (Domain Models) 和视图模型 (View Models),并调整这些类来创建您的应用程序,而无需编写大量代码。

工作演示

您可以访问 http://www.razisyed.com/entityui 获取工作演示和更多详细信息。

源代码也可在 GitHub 上找到: https://github.com/razisyed/EntityUi

背景

我最初在几年前开始使用 ASP.NET 开发 EntityUi,并编写了一些简单的代码来使用反射渲染 UI。那是最初发布的那篇文章。然而,自 EntityUI 发布以来,很多东西都发生了变化。MVC 和 Knockout 已经流行了一段时间,它们都是实现 MVVM 模式的出色工具。

因此,EntityUi 现在是一个使用 MVC 和 Knockout 从模型自动生成 UI 的项目。它基本上旨在成为一个快速应用程序开发工具,不仅可以快速生成常见的 CRUD 页面,还可以尝试处理更高级的场景。

先决条件

这是为 Microsoft MVC 项目准备的。您应该熟悉 MVVM 模式、领域模型 (Domain Model)、视图模型 (View Model),并且需要了解 Knockout 才能理解和使用一些高级功能。您还需要了解存储库模式 (Repository pattern) 和 Microsoft Entity Framework Code First 才能完全理解这一切是如何工作的。我们将使用 NuGet 下载 EntityUi 包,并使用 Bootstrap 来获得漂亮的布局。

Using the Code

我将通过一个全新的项目来演示其用法,以保持简单。启动一个空的 MVC 项目,然后在解决方案中添加 2 个类库项目,一个用于领域模型,另一个用于存储库。

然后,将 EntityUi 从 nuget 添加到解决方案中的领域项目和存储库项目中。要安装 EntityUi,请在 程序包管理器控制台 中运行以下命令:

PM> Install-Package EntityUi

在空的 MVC 项目中,安装 EntityUi.Web 包。

PM> Install-Package EntityUi.Web

EntityUi 包具有以下核心概念:

  • DomainModelBase - 您的领域模型(实际上是数据模型)对象需要继承的基类。
  • ViewModelBase - 您的视图模型对象需要继承的基类。
  • ControllerBase - 您的控制器的基类,它内置了 CRUD 方法。
  • RepositoryBase - 您的存储库的基类,它使用 Entity Framework 内置了 CRUD 方法。

EntityUi.Web 包添加了使用 EntityUi 所需的几个布局和模板。

接下来,我们需要编写领域模型和存储库方法。

在本例中,我们将使用以下示例“Department”类。我从 MSDN Entity Framework Code First Fluent API 示例 中选取了它。

    public class Department : DomainModelBase
    {
        public Department()
        {
            Courses = new HashSet<Course>();
        }
 
        public string Name { get; set; }
        public decimal Budget { get; set; }
        public DateTime StartDate { get; set; }
        public int? Administrator { get; set; }
 
        // Navigation property
        public ICollection<Course> Courses { get; set; }
    } 

正如您所见,它继承自 DomainModelBase 类。

接下来,我们设置存储库。添加您的 Context 类,继承自 Entity Framework 的 DbContext 类,并为 Department 添加一个简单的 Repository 类,“DepartmentRepository”。

 public class DataContext : DbContext
    {
        public DbSet<Department> Departments { get; set; } 
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<DataContext>());
        } 
    }  

public class DepartmentRepository : RepositoryBase<Department, DataContext>
    {
        protected override DataContext GetContext()
        {
            return new DataContext();
        }
    } 

DataContext 类是一个非常简单的 Context 类,目前只有一个 Departments 属性。

Repository 也是一个非常简单的实现。此类除了 GetContext 之外没有其他方法,它继承自 DomainModelBase 类。正如您所见,继承自 RepositoryBase 时,您必须向基类提供实体名称和 DataContext,以便它知道正在处理什么。

现在我们来处理视图,并添加模型、视图和控制器类。我始终提倡使用单独的领域模型和视图模型类,即使对于简单情况它们大部分是相同的。我们将使用 AutoMapper 来轻松地在领域模型和视图模型之间进行转换。

所以这是 Controller 类。

    public class DepartmentController : ControllerBase<Department, DepartmentView, DataContext>
    {
        public DepartmentController()
        {
            Repository=new DepartmentRepository();
        }
    } 

控制器与类一样,继承自 ControllerBase。它需要知道领域模型、视图模型和 DataContext

您需要映射领域模型和视图模型之间的属性,以便相互转换。EntityUi 会自动为您创建一个默认的 Mapper,如果属性名称相同,则会复制值。

如果需要,您还可以在 global.aspx 中为 AutoMapper 设置领域模型和视图模型对象之间的自定义映射。

            Mapper.CreateMap<Department, DepartmentView>();
            Mapper.CreateMap<DepartmentView, Department>()
          .ForMember(d => d.Id, o => o.Condition(s => s.Id > 0))
                  .ForMember(d => d.Courses, o => o.Ignore());; 

上面的代码是一个使用 AutoMapper 的简单领域视图到模型视图的映射。在后台,它基本上使用反射将属性值从一个对象复制到另一个对象。基本上,通过这个工具,我们告诉 EntityUi 如何在领域和模型视图对象之间进行转换。

现在您应该能够构建并运行应用程序,当您导航到“department”时,它应该会为您渲染部门屏幕,其中包括完整的 CRUD 功能,包括渲染页面并将其保存到数据库。

所以,这是 EntityUi 最基本和最简单的用法。现在让我们尝试一些更有趣的东西。

使用下拉列表

以下是如何通过修改视图模型来使用下拉列表。让我们从添加 Course 概念开始,如下所示:

这是领域模型。

  public class Course : DomainModelBase
    {
        public Course()
        {
            Instructors = new HashSet<Instructor>();
        }

        public string Title { get; set; }
        public int Credits { get; set; }

        // Foreign key
        public int DepartmentID { get; set; }

        // Navigation properties
        public Department Department { get; set; }
        public ICollection<Instructor> Instructors { get; set; }

    } 

正如您所见,它有一个 Department 作为导航属性,这表明在 UI 中,我们希望看到一个下拉列表,其中列出了所有 Departments,并且用户应该能够选择 department

这是 RepositoryController

    public class CourseRepository : RepositoryBase<Course, DataContext>
    {
        protected override DataContext GetContext()
        {
            return new DataContext();
        }
    } 

它们都只是基本的骨架,只需继承自 EntityUiRepositoryBaseController Base

现在,这是视图模型。

 public class CourseView : ViewModelBase
    {
        public string Title { get; set; }
        public int Credits { get; set; }

        public DropDown Departments { get; set; }

        public CourseView()
        {
            Departments = new DropDown
            {
                Items = (new DepartmentRepository())
                          .List()
                          .ToList()
                          .ConvertAll(x => new SelectListItem
                          {
                              Text = x.Name,
                              Value = x.Id.ToString()
                          })
            };
        }
    } 

这有点不同。要渲染 Department 的下拉列表,我们将 Departments 属性定义为 EntityUi 的辅助类型“DropDown”。另外,在构造函数中,我们用来自数据库的 Departments 列表加载了它。我希望代码是自明的,并且不需要太多解释。我们所做的只是在 DepartmentRepository 上调用“List()”方法(由 EntityUi 提供),以获取所有 Departments,并使用“ConvertAll()”方法(由 Linq 提供)将其转换为 SelectListItem

下一个有趣的部分将是我们将视图模型和领域视图进行映射的地方。以下是需要添加到 Global.asax 的代码:

  Mapper.CreateMap<CourseView, Course>()
        .ForMember(d => d.Id, o => o.Condition(s => s.Id > 0))
        .ForMember(d => d.DepartmentID, o => o.MapFrom(s => s.Departments.SelectedId))
        .ForMember(d => d.Department, o => o.Ignore());

  Mapper.CreateMap<Course, CourseView>()
        .ForMember(d => d.Departments, o => o.Ignore())
        .AfterMap((s, d) => d.Departments.SelectedId = s.DepartmentID.ToString()); 

这实际上是 Auto Mapper 的一个相当高级的用法。您可能需要查阅 AutoMapper 的文档。

在第一个映射语句中,我们将 CourseView(视图模型)映射到 Course(领域模型)。有趣的部分在于,我们将域的 Department ID 映射到视图的 Departments 下拉列表中的 SelectedId 属性。在第二个映射中,从域到视图模型,它是完全相反的。

这基本上就是所需的全部代码。如果您现在运行并导航到“Courses”,您将能够添加/编辑/删除,并且 Department 将显示为一个下拉列表。

添加用户界面交互

到目前为止,我们已经看了一些基本的 CRUD 功能。其理念是,通过仅处理视图模型,可以实现比 CRUD 更多的功能。因此,假设我们有一个业务需求,即仅当分配了 Budget 时,Department 才要求提供预算,否则,不显示预算输入。

处理这种情况的最佳方法是在视图中使用 JavaScript。处理这些场景的最简单方法之一是使用 Knockout。EntityUi 允许您通过使用 DataBind 数据注解来为任何属性添加 Knockout 绑定。

因此,我们可以通过简单地修改 Department 视图来实现此要求,如下所示:

 public class DepartmentView : ViewModelBase
 {
    public string Name { get; set; }
    public bool HasBuget { get; set; }
    [DataBind("visible:HasBuget()")]
    public decimal Budget { get; set; }
    public DateTime StartDate { get; set; }
 } 
  

因此,我在这里所做的是,首先我添加了一个布尔属性 HasBudget。这将渲染为一个 checkbox

接下来,我添加了 DataBind 属性,并提供了我通常会添加到视图的 Knockout 绑定。EntityUi 会自动渲染它。您需要熟悉 Knockout 绑定才能充分利用此功能,如果还不熟悉,请访问 www.knockoutjs.com 获取文档。我们所做的只是将可见性设置为 HasBudget 属性。在后台,EntityUi 使用 knockoutmvc 将每个视图模型设置为 Knockout 视图模型,使每个属性都成为可观察的。

此代码更改将执行以下操作:当您以编辑模式查看页面时,如果选中“HasBudget”复选框,将显示预算输入字段和标签;如果取消选中,则会隐藏它们。

摘要

因此,希望通过上面提供的详细信息,您可以了解如何使用 EntityUi 进行快速应用程序开发,利用工具处理从处理数据到用户界面的所有代码编写方面。

作为开发人员,主要任务是编写领域模型和视图模型。然后,通过添加 Attributes 和/或 Fluent API 配置以及遵循约定,其他大部分工作都将完成,我们将拥有一个功能齐全的应用程序。

EntityUi 也非常灵活,并为开发人员提供了完全的控制权。开发人员可以覆盖或在任何类中添加任何方法,无论是存储库、控制器还是视图。您也可以在不使用 EntityUi 的情况下,非常轻松地在同一个应用程序中编写完整的页面或类,或者在利用 EntityUi 框架的视图和控制器中添加内容。

参考文献

我使用许多不同的开源库编写了 EntityUi。以下是一些主要的库:

© . All rights reserved.