做一个后台管理网站,用Asp.Net MVC做,最后用WCF给CS客户端。
Controller和View都用VS自动生成的,试着在DbContext外加了个BLL层,当前还看不到必要性,先放着。
基本的类结构弄好后,开始正式做界面。
第一个问题,树机构的增删改查。
参考:
MVC+EF处理树形结构
有树结构的类是
/// <summary>
/// 机构
/// </summary>
public class Department
{
public int Id { get; set; }
[Display(Name="机构名")]
public string Name { get; set; }
[Display(Name = "排序")]
public int ShowOrder { get; set; }
[Display(Name = "上级机构")]
public virtual Department Parent { get; set; }
}
初始化代码
Department dep1 = new Department() { Id = 0, Name = "机构", ShowOrder = 0, Parent = null };
Department dep2 = new Department() { Id = 1, Name = "机构1", ShowOrder = 0, Parent = dep1 };
Department dep3 = new Department() { Id = 2, Name = "机构2", ShowOrder = 1, Parent = dep1 };
Department dep4 = new Department() { Id = 3, Name = "机构3", ShowOrder = 2, Parent = dep1 };
Department dep5 = new Department() { Id = 4, Name = "机构4", ShowOrder = 0, Parent = dep2 };
Department.AddRange(new List<Department>() { dep1, dep2, dep3, dep4, dep5 });
表结构
无论是给前端还是给CS,Parent_Id属性都要在对象中明确声明,因为如果用Parent属性传递,Parent属性的序列化过程可能是递归的。
改为
/// <summary>
/// 机构
/// </summary>
public class Department
{
public int Id { get; set; }
[Display(Name="机构名")]
public string Name { get; set; }
[Display(Name = "排序")]
public int ShowOrder { get; set; }
[Display(Name = "上级机构")]
public virtual Department Parent { get; set; }
public int? ParentId { get; set; }
}
注意:int? 如果改成 int 初始化数据或者添加数据时会出问题
“System.Data.Entity.Infrastructure.DbUpdateException”类型的异常在 EntityFramework.dll 中发生,但未在用户代码中进行处理
其他信息: 无法确定依赖操作的有效顺序。由于外键约束、模型要求或存储生成的值,因此可能存在依赖关系。
这个提示我是看不出和int?有什么关系的
按我理解没有?就变成了不能为空,我的初始化数据中有个为空的,所以就出错了。
另外有个外键约束在ParentId上,不能为空,根节点的父不存在的,也就出错了。
继续树显示问题
为了递归获取子节点,添加Children属性
public class Department
{
public int Id { get; set; }
[Display(Name="机构名")]
public string Name { get; set; }
[Display(Name = "排序")]
public int ShowOrder { get; set; }
[Display(Name = "上级机构")]
public virtual Department Parent { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual ICollection<Department> Children { get; set; }
}
添加HtmlHelper扩展方法
namespace System.Web.Mvc
{
public static class MyHtmlHelper
{
public static MvcHtmlString Tree(this HtmlHelper html, Department treeModel)
{
return BindTree(treeModel);
}
private static MvcHtmlString BindTree(Department treeModel)
{
StringBuilder sb = new StringBuilder();
if (treeModel != null)
{
sb.Append("<ul>");
List<Department> list = treeModel.Children.ToList();
foreach (var item in list)
{
sb.Append("<li>");
sb.Append(item.Name);
sb.Append("</li>");
sb.Append(BindTree(item));
}
sb.Append("</ul>");
}
MvcHtmlString mstr = new MvcHtmlString(sb.ToString());
return mstr;
}
}
}
这个方法不够通用,改造一下,写个接口
public interface ITreeNode<T>
{
string Name { get; set; }
ICollection<T> Children { get; set; }
}
继承接口:
public class Department: ITreeNode<Department>
面向接口编程:
namespace System.Web.Mvc
{
public static class MyHtmlHelper
{
public static MvcHtmlString Tree<T>(this HtmlHelper html, ITreeNode<T> treeModel) where T : ITreeNode<T>
{
return BindTree(treeModel);
}
private static MvcHtmlString BindTree<T>(ITreeNode<T> treeModel) where T : ITreeNode<T>
{
StringBuilder sb = new StringBuilder();
if (treeModel != null)
{
sb.Append("<ul>");
List<T> list = treeModel.Children.ToList();
foreach (T item in list)
{
sb.Append("<li>");
sb.Append(item.Name);
sb.Append("</li>");
sb.Append(BindTree(item));
}
sb.Append("</ul>");
}
MvcHtmlString mstr = new MvcHtmlString(sb.ToString());
return mstr;
}
}
}
使用上和原来的函数一样。
Controller中添加一个Action
public ActionResult Tree()
{
return View(db.Departments.GetRoot());
}
GetRoot()是获取根节点,多个根节点的情况后面在改造。
添加一个View,使用Tree扩展函数
@model Location.Model.Department
@{
ViewBag.Title = "Tree";
}
<h2>Tree</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<div>
@Html.Tree(Model)
</div>
结果:
下一个问题,创建子节点