《在Orchard中创建一个HelloWorld模块》一文中我们介绍了如何创建一个非常简单的HelloWorld模块。当时HelloWorld模块只是显示了一段在Code中指定的文字。本文将对HelloWorld模块进行升级,让所显示的文字可以在后台维护。为了实现这个功能,我们需要进行以下工作:
1、建立一个数据表,存储这段文字。
2、在Orchard后台中建立一个维护界面,实现编辑显示文字的功能。
3、修改前台代码,将直接在Code中写死的文字改为从数据库中读取。
创建数据库安装文件
在Orchard中提供了一套模块的安装和升级机制。当模块需要用到数据库的时候,Orchard通过一个Migrations.cs文件去创建和更新数据库。在Orchard命令行工具中输入以下命令,即可创建Migrations.cs文件模板。
Codegen datamigration MyCompany.HelloWorld
修改代码如下:
Migrations.cs
using System;
using System.Collections.Generic;
using System.Data;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
namespace MyCompany.HelloWorld
{
/// <summary>
/// 数据库创建升级文件
/// </summary>
public class Migrations : DataMigrationImpl
{
/// <summary>
/// 由于先的一个版本没有数据库所以这个地方空着
/// </summary>
/// <returns>返回版本号</returns>
public int Create()
{
return 1;
}
/// <summary>
/// 升级模块,创建一个数据表存储HelloWorld模块所需要显示的文字
/// </summary>
/// <returns>返回版本号</returns>
public int UpdateFrom1()
{
// 创建存储HelloWorld文字的数据库
SchemaBuilder.CreateTable("TextRecord", table => table
.Column<int>("Id", column => column.PrimaryKey().Identity()) //定义一个Id键
.Column<string>("Content", column => column.WithLength(200)) //定义一个内容字段,长度200
);
return 2;
}
}
using System.Collections.Generic;
using System.Data;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
namespace MyCompany.HelloWorld
{
/// <summary>
/// 数据库创建升级文件
/// </summary>
public class Migrations : DataMigrationImpl
{
/// <summary>
/// 由于先的一个版本没有数据库所以这个地方空着
/// </summary>
/// <returns>返回版本号</returns>
public int Create()
{
return 1;
}
/// <summary>
/// 升级模块,创建一个数据表存储HelloWorld模块所需要显示的文字
/// </summary>
/// <returns>返回版本号</returns>
public int UpdateFrom1()
{
// 创建存储HelloWorld文字的数据库
SchemaBuilder.CreateTable("TextRecord", table => table
.Column<int>("Id", column => column.PrimaryKey().Identity()) //定义一个Id键
.Column<string>("Content", column => column.WithLength(200)) //定义一个内容字段,长度200
);
return 2;
}
}
这样我们再次登陆管理后台的时候会有升级模块的提示
点击Update即可升级模块,在数据库中就可以看见我们刚刚创建的表了。
如果我们以后还需升级这个HelloWorld模块,只用在Migrations.cs文件中添加一个UpdateFrom2方法返回3即可,后续还有升级就以此类推。
创建数据实体及业务逻辑层代码
在Orchard中数据实体的命名规则通常是:实体名+Record构成。遵循此规则我们在模块目录下的Models目录中添加一个TextRecord.cs文件,代码如下:
TextRecord.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement.Records;
using Orchard.ContentManagement;
using System.ComponentModel.DataAnnotations;
namespace MyCompany.HelloWorld.Models
{
public class TextRecord
{
public virtual int Id { get; set; }
public virtual string Content { get; set; }
}
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement.Records;
using Orchard.ContentManagement;
using System.ComponentModel.DataAnnotations;
namespace MyCompany.HelloWorld.Models
{
public class TextRecord
{
public virtual int Id { get; set; }
public virtual string Content { get; set; }
}
在Orchard中是通过Nhibernate进行数据库操作的,但是我们在进行模块开发的时候并不需要直接使用Nhibernate,Orchard对其进行了封装。我们只需要通过IRepository<T>接口就可以对相应实体T所对应的数据表进行增、删、改、查的操作了。另外Orchard中的对象实例化,大多都是通过依赖注入去完成的。所以我们需要创建业务逻辑层对象的时候需要首先定义其接口。这样我们在使用该业务对象的时候就直接使用接口即可,Orchard会自动找到相应的类并实例化。
首先在模块目录中创建一个Services目录来存放业务逻辑层代码,然后添加一个ITextService.cs文件,输入以下代码来定义一个接口:
ITextService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Orchard;
using MyCompany.HelloWorld.Models;
namespace MyCompany.HelloWorld.Services
{
/// <summary>
/// 定义业务层接口(为了实现依赖注入还需继承IDependency接口)
/// </summary>
public interface ITextService : IDependency
{
/// <summary>
/// 这里不考虑多条数据的情况,仅默认获取第一条数据
/// </summary>
/// <returns></returns>
TextRecord GetText();
/// <summary>
/// 更新数据
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
TextRecord UpdateText(string content);
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Orchard;
using MyCompany.HelloWorld.Models;
namespace MyCompany.HelloWorld.Services
{
/// <summary>
/// 定义业务层接口(为了实现依赖注入还需继承IDependency接口)
/// </summary>
public interface ITextService : IDependency
{
/// <summary>
/// 这里不考虑多条数据的情况,仅默认获取第一条数据
/// </summary>
/// <returns></returns>
TextRecord GetText();
/// <summary>
/// 更新数据
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
TextRecord UpdateText(string content);
}
再在Services目录中添加一个TextService.cs文件,输入以下代码来实现此接口:
TextService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using JetBrains.Annotations;
using Orchard.Data;
using MyCompany.HelloWorld.Models;
namespace MyCompany.HelloWorld.Services
{
[UsedImplicitly]
public class TextService : ITextService
{
/// <summary>
/// IRepository可以把它理解为数据访问层对象,它提供了相应实体的增删改查操作。
/// </summary>
private readonly IRepository<TextRecord> _textRepository;
public TextService(IRepository<TextRecord> textRepository)
{
_textRepository = textRepository;
}
#region ITextService 成员
public TextRecord GetText()
{
return _textRepository.Table.FirstOrDefault();
}
public TextRecord UpdateText(string content)
{
var result = GetText();
if (result == null)
{
result = new TextRecord { Content = content };
_textRepository.Create(result);
}
else
{
result.Content = content;
_textRepository.Update(result);
}
return result;
}
#endregion
}
using System.Collections.Generic;
using System.Linq;
using System.Web;
using JetBrains.Annotations;
using Orchard.Data;
using MyCompany.HelloWorld.Models;
namespace MyCompany.HelloWorld.Services
{
[UsedImplicitly]
public class TextService : ITextService
{
/// <summary>
/// IRepository可以把它理解为数据访问层对象,它提供了相应实体的增删改查操作。
/// </summary>
private readonly IRepository<TextRecord> _textRepository;
public TextService(IRepository<TextRecord> textRepository)
{
_textRepository = textRepository;
}
#region ITextService 成员
public TextRecord GetText()
{
return _textRepository.Table.FirstOrDefault();
}
public TextRecord UpdateText(string content)
{
var result = GetText();
if (result == null)
{
result = new TextRecord { Content = content };
_textRepository.Create(result);
}
else
{
result.Content = content;
_textRepository.Update(result);
}
return result;
}
#endregion
}
创建管理后台界面
在Orchard中如果需要在后台添加一个维护界面,需要通过添加一个AdminMenu.cs文件来实现。这个文件可以定义相应模块所拥有的菜单和对应的路由。AdminMenu.cs的代码如下:
AdminMenu.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.UI.Navigation;
using Orchard.Security;
using Orchard.Localization;
namespace MyCompany.HelloWorld
{
public class AdminMenu : INavigationProvider
{
public Localizer T { get; set; }
#region INavigationProvider 成员
/// <summary>
/// 指定这个菜单是一个管理菜单
/// </summary>
public string MenuName
{
get { return "admin"; }
}
public void GetNavigation(NavigationBuilder builder)
{
builder.AddImageSet("helloworld") //设置菜单图标(Orchard中默认约定调用Styles目录下的menu.xxxxxx-admin.css样式文件来显示菜单前面的图标)
.Add(
T("Hello World"), //菜单文本
"5", //菜单位置(Orchard会根据这个值对菜单进行排序)
menu => menu.Action("Index", "Admin", new { area = "MyCompany.HelloWorld" }) //定义菜单所执行的路由
);
}
#endregion
}
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.UI.Navigation;
using Orchard.Security;
using Orchard.Localization;
namespace MyCompany.HelloWorld
{
public class AdminMenu : INavigationProvider
{
public Localizer T { get; set; }
#region INavigationProvider 成员
/// <summary>
/// 指定这个菜单是一个管理菜单
/// </summary>
public string MenuName
{
get { return "admin"; }
}
public void GetNavigation(NavigationBuilder builder)
{
builder.AddImageSet("helloworld") //设置菜单图标(Orchard中默认约定调用Styles目录下的menu.xxxxxx-admin.css样式文件来显示菜单前面的图标)
.Add(
T("Hello World"), //菜单文本
"5", //菜单位置(Orchard会根据这个值对菜单进行排序)
menu => menu.Action("Index", "Admin", new { area = "MyCompany.HelloWorld" }) //定义菜单所执行的路由
);
}
#endregion
}
此外我们还需要添加这个维护界面所对应的Controller、View以及View对应的ViewModel。这些都是一些MVC的基本知识,在上一篇的HelloWord模块中已有介绍,在此就不重复贴代码了。大家可以下载本文示例代码查看。另外修改前台Controller代码也不赘述。
使用升级后的HelloWorld模块
首先,进入管理后台,我们就可以看见“Hello World”的管理菜单,点击即可进入HelloWorld界面。
保存文字,还是在前台访问 /HelloWorld 地址,即可看见效果。
结论
通过本文示例,我们又学习了Orchard中的一些知识。包括:如何安装和升级模块所使用的数据库、如何在后台添加一个管理界面、如何存取数据等。但是本文所介绍的这些知识,都只是触及了一下皮毛,后续可就这几个知识点再次展开深入的学习,此文权当抛砖引玉之用。
本文示例下载:点击这里
(以上内容使用于:Orchard 1.1版本)
参考文档
NHibernate 官网:http://nhforge.org
博客园中NHibernate专题网站:http://kb.cnblogs.com/zt/nhibernate/
==========================================
作者:二十四画生
转载请注明来源于博客园——二十四画生的Blog,并保留有原文链接。