EntityUI 自动 UI 生成器
这是“使用 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
。
这是 Repository
和 Controller
。
public class CourseRepository : RepositoryBase<Course, DataContext>
{
protected override DataContext GetContext()
{
return new DataContext();
}
}
它们都只是基本的骨架,只需继承自 EntityUi
的 RepositoryBase
和 Controller 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
。以下是一些主要的库:
- MVC Bootstrap 包 twitter.bootstrap.mvc4,作者 Eric Hexter
(https://nuget.net.cn/packages/twitter.bootstrap.mvc4/) - AutoMapper,作者 Jimmy Bogard
(https://nuget.net.cn/packages/AutoMapper/3.0.0) - knockoutmvc (http://knockoutmvc.com/)