从自引用表中选择并转换为视图模型

本文关键字:转换 视图 模型 选择 自引用 | 更新日期: 2023-09-27 18:36:31

如何

选择自引用表的所有级别作为视图模型。 如果最大级别是 2 或 3,那么我可以通过多次调用Select来做到这一点,但我有 4-5 级菜单,我认为应该有更好的解决方案来做到这一点并选择所有级别。

这是我的视图模型:

public class MenuViewModel
{
    public MenuViewModel()
    {
        Childs = new HashSet<MenuViewModel>();
    }
    public int Id{ get; set; }
    public string Title { get; set; }
    public string Url { get; set; }
    public ICollection<MenuViewModel> Childs { get; set; }
}

这是我的菜单类:

public class Menu
{
    public Menu()
    {
        Childs = new HashSet<Menu>();
    }
    public int Id{ get; set; }
    public string Title { get; set; }
    public string Url { get; set; }
    public string Description { get; se; }
    public byte[] Icon { get; set; }
    public int Order { get; set; }
    public ICollection<Menu> Childs { get; set; }
}

var viewModel = _dataContext.Menus
.Select(x => new MenuViewModel 
{ 
    Id = x.Id, 
    Title = x.Title, 
    Child = ???
}
.ToList();

从自引用表中选择并转换为视图模型

使用 EF 时,可以按以下方式执行以下操作:

public class BlogComment
{
    public int Id { set; get; }
    [MaxLength]
    public string Body { set; get; }
    public virtual BlogComment Reply { set; get; }
    public int? ReplyId { get; set; }
    public ICollection<BlogComment> Children { get; set; }
}    

using (var ctx = new MyContext())
            {
                var list = ctx.BlogComments
                          //.where ...
                          .ToList() // fills the childs list too
                          .Where(x => x.Reply == null) // for TreeViewHelper                        
                          .ToList();
            }

通过这种方式,您不需要使用递归查询,但据我所知,当使用视图模型获取数据时,EF的动态代理被破坏了。

关于上面的例子:只需选择一个评论列表,然后

.Where(x=>x.Reply==null).Tolist()

EF 填充注释的子属性。

参考

假设Id属性是唯一的,你可以分两次完成:

  1. 创建不带子项但具有关联子项 ID 的视图模型项。从该数据中创建字典,该字典将允许您按其 id 获取任何视图模型。此字典中的值将是创建的视图模型及其子 ID 。
  2. 对于每个视图模型项,使用子 ID 获取关联的视图模型项。

像这样:

var tempModels = _dataContext
    .Menus
    .Select(menu => new
    {
        childrenIds = menu.Childs.Select(item => item.Id).ToArray(),
        viewModel =
            new MenuViewModel
            {
                Id = menu.Id,
                Title = menu.Title
            }
    })
    .ToDictionary(
        keySelector: item => item.viewModel.Id);
var viewModels = tempModels
    .Select(kv =>
        {
            var viewModel = kv.Value.viewModel;
            viewModel.Childs = kv
                .Value
                .childrenIds
                .Select(childId => 
                    tempModels[childId].viewModel)
                .ToList();
            return viewModel;
        })
    .ToList();

对于深度问题,您可以在模型中使用一个像 Depth 这样的 int 属性,然后您可以获取如下数据:

public class BlogComment
{
    public int Id { set; get; }
    [MaxLength]
    public string Body { set; get; }
    public int Depth{get;set}
    public virtual BlogComment Reply { set; get; }
    public int? ReplyId { get; set; }
    public ICollection<BlogComment> Children { get; set; }
}    

using (var ctx = new MyContext())
            {
                var list = ctx.BlogComments
                          .Where(a=>a.Depth<2)
                          .ToList() // fills the childs list too
                          .Where(x => x.Reply == null) // for TreeViewHelper                        
                          .ToList();
            }

为了在这个Senario中使用视图模型,我使用自动映射器进行测试,但是当使用viewModel选择数据时,EF生成的动态代理被销毁。

请注意此问题