Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Linq类别和子类别_C#_Linq - Fatal编程技术网

C# Linq类别和子类别

C# Linq类别和子类别,c#,linq,C#,Linq,问题是,我不知道如何使用LINQ获取所有类别和子类别,并将它们添加到列表中,以便在视图中显示它们 public class Category { public int ID { get; set; } public string Title { get; set; } public int? ParentID { get; set; } public virtual Category Parent { get; set; } } 目前我只有这个方法来获取所有类别

问题是,我不知道如何使用LINQ获取所有类别和子类别,并将它们添加到列表中,以便在视图中显示它们

public class Category
{
    public int ID { get; set; }
    public string Title { get; set; }
    public int? ParentID { get; set; }
    public virtual Category Parent { get; set; }
}
目前我只有这个方法来获取所有类别

public async Task<IEnumerable<Category>> GetAllCategories()
    {
        return await _context.Categories.ToListAsync();
    }
公共异步任务GetAllCategories() { return wait_context.Categories.toListSync(); } 这就是我想要实现的目标:


层次结构树结构并不真正适合运行LINQ查询,因为(不幸的是)您需要为要包含的每个层次结构级别扩展查询

此查询应将所有顶级类别作为组及其直接子级提供给您:

var query = from category in _context.Categories
            where category.ParentID == null
            from subCategory in _context.Categories
            where subCategory == category.ID
            group subCategory by category;
如果您只有两个层次结构,这应该可以很好地工作,但是要真正获得任何顺序的树结构,您需要展平层次结构,这通常是使用递归函数完成的,其中对它的每次调用(本身)都展平树的一个节点

对于这种结构,标准SQL查询或LINQ查询并不能真正解决它。然而,实体框架(可能还有其他ORM解决方案)将为您完成所有工作

您可以在模型中创建两个属性正确的导航属性,如下所示:

public virtual IEnumerable<Category> SubCategories { get; set; }
public virtual Category ParentCategory { get; set; }
公共虚拟IEnumerable子类别{get;set;}
公共虚拟类别ParentCategory{get;set;}
但是,如果您选择而不是在模型中包含导航属性,则需要以艰难的方式执行此操作,每次调用递归函数时都向数据层发出请求

public void RenderSubCategoriesAsHtml(int? parentID = null)
{
    var children =
        from category in _context.Categories
        where category.ParentID == parentID
        select category;

    if (children.Any())
    {
        Response.WriteLine("<ul>");
        foreach (var child in children)
        {
            Response.WriteLine("<li><a href=\"#addProperUrl\">");
            Response.WriteLine(Server.EncodeHtml(child.Title));
            Response.WriteLine("</a>");
            RenderSubCategoriesAsHtml(child.ID);
            Response.WriteLine("</li>");
        }
        Response.WriteLine("</ul>");
    }
}
public void RenderSubCategoriesAsHtml(int?parentID=null)
{
var儿童=
来自_context.Categories中的类别
其中category.ParentID==ParentID
选择类别;
if(children.Any())
{
响应。WriteLine(
    ); foreach(儿童中的儿童变量) { 响应。WriteLine(
  • ); RenderSubCategoriesAsHtml(child.ID); 响应。WriteLine(“
  • ”); } 响应。WriteLine(“
”); } }

只需将对
Response.WriteLine
的调用更改为更适合应用程序架构的调用。

EF有一种方法可以做到这一点。但是在
类别
子类别

var all categoriesWithSubCategories =  _context.Categories.Include("Subcategory").ToList();
现在,当您从
categories with subcategories
列表中选择一个类别时,您将可以访问属于所选类别的所有子类别

添加更多细节以进一步解释

正如我前面提到的,要做到这一点,您必须在同一个表上有一个FK关系

这意味着您的
ParentId
字段与您的
Id
字段(即PK字段)具有外键关系

现在稍微更改实体类以表示上述关系

public partial class Category
{
    public Category()
    {
        this.SubCategory = new HashSet<Category>();
    }

    public int Id { get; set; }
    public string Title { get; set; }
    public Nullable<int> ParentId { get; set; }

    public virtual ICollection<Category> SubCategory { get; set; }
    public virtual Category ParentCategory { get; set; }
}
公共部分类类别
{
公共类别()
{
this.SubCategory=new HashSet();
}
公共int Id{get;set;}
公共字符串标题{get;set;}
公共可为空的ParentId{get;set;}
公共虚拟ICollection子类别{get;set;}
公共虚拟类别ParentCategory{get;set;}
}

完成后,您只需要一行Linq(如上所述)就可以为您的类别和子类别构建完美的树层次结构。

因此,如果我从以下数据开始:

public async Task<IEnumerable<Category>> GetAllCategories()
    {
        return await _context.Categories.ToListAsync();
    }
var categories = new List<Category>()
{
    new Category() { ID = 0, ParentID = null, Title = "First Link" },
    new Category() { ID = 1, ParentID = null, Title = "Second Link" },
    new Category() { ID = 2, ParentID = null, Title = "Third Link" },
    new Category() { ID = 3, ParentID = null, Title = "Fourth Link" },
    new Category() { ID = 4, ParentID = null, Title = "Fifth Link" },
    new Category() { ID = 5, ParentID = 0, Title = "First Child Link" },
    new Category() { ID = 6, ParentID = 0, Title = "Second Child Link" },
    new Category() { ID = 7, ParentID = 0, Title = "Third Child Link" },
    new Category() { ID = 8, ParentID = 6, Title = "First Grandchild Link" },
    new Category() { ID = 9, ParentID = 6, Title = "Second Grandchild Link" },
    new Category() { ID = 10, ParentID = 6, Title = "Third Grandchild Link" },
};
这将创建一个可用于查找任何父ID的所有子项的查找。在您的情况下,您应该能够只执行
\u context.Categories.ToLookup(x=>x.ParentID)。您可能需要在
.ToLookup
之前弹出一个
.ToArray()

好的是,这只会对数据库进行一次访问

现在递归遍历数据变得很容易。以下是三种方法:

(一)

Func formatTree=null;
formatTree=(l,p,i)=>
从c到l[p]
从新[]{.padlefit(i*4)+c.Title}.Concat(formatTree(l,c.ID,i+1))中的t开始
选择t;
(二)

public IEnumerable FormatTree(ILookup查找、int?父级、int缩进)
{
返回
在查找[parent]中从c开始
从新[]{.PadLeft(缩进*4)+c.Title}.Concat(格式树(查找,c.ID,缩进+1))中的t开始
选择t;
}
(三)

public IEnumerable FormatTree2(ILookup查找、int?父级、int缩进)
{
foreach(查找[parent]中的变量类别)
{
收益率返回“.PadLeft(缩进*4)+类别.标题;
foreach(FormatTree2中的变量子代(查找,category.ID,缩进+1))
{
产量回报后代;
}
}
}
这三种语言都以相同的方式做相同的事情,只是语法不同

我得到这个输出:

First Link First Child Link Second Child Link First Grandchild Link Second Grandchild Link Third Grandchild Link Third Child Link Second Link Third Link Fourth Link Fifth Link 第一环节 第一个子链接 第二子链接 第一孙子链接 第二孙链接 第三孙链接 第三个子链接 第二环节 第三环节 第四环 第五环
不清楚您的确切输出是什么-我假设您不希望创建PNG图像-但您应该能够使用它来获得所需的内容。

好的,忘记Linq,并展示如何使用经典循环。。。这将是解决您的问题的第一步…您的数据库中是否设置了外键?如果是这样的话,这应该不难做到,Linq。如果你已经创建了样本数据(在有效的C#代码中)来进行工作,那将是非常棒的。谢谢,我想我是从你所说的话中了解到的,如果我尝试使用递归函数可能会更好。我不会说标准SQL有问题,因为递归查询是完全标准的。问题可能出在ORM方面。完美标准?如果没有交叉应用,你将如何解决它?我不确定我们是否在谈论同一件事,我正在谈论的是:我刚刚遇到了一件奇怪的事情,我真的不知道为什么会发生这种情况
public IEnumerable<string> FormatTree(ILookup<int?, Category> lookup, int? parent, int indent)
{
    return
        from c in lookup[parent]
        from t in new[] { "".PadLeft(indent * 4) + c.Title }.Concat(FormatTree(lookup, c.ID, indent + 1))
        select t;
}
public IEnumerable<string> FormatTree2(ILookup<int?, Category> lookup, int? parent, int indent)
{
    foreach (var category in lookup[parent])
    {
        yield return "".PadLeft(indent * 4) + category.Title;
        foreach (var descendant in FormatTree2(lookup, category.ID, indent + 1))
        {
            yield return descendant;
        }
    }
}
First Link First Child Link Second Child Link First Grandchild Link Second Grandchild Link Third Grandchild Link Third Child Link Second Link Third Link Fourth Link Fifth Link