LINQ查询查找相关数据

时间:2018-01-03 13:01:11

标签: c# linq entity-framework-core

我之前在Stack Overflow上获得了一些关于递归产品类别树视图的帮助,这是有效的:

实体模型:

public class ProductCategory
{
    public int Id { get; set; }
    public int SortOrder { get; set; }
    public string Title { get; set; }

    [ForeignKey(nameof(ParentCategory))]
    public int? ParentId { get; set; }

    public ProductCategory ParentCategory { get; set; } //nav.prop to parent
    public ICollection<ProductCategory> Children { get; set; } //nav. prop to children

    public List<ProductInCategory> ProductInCategory { get; set; }
}

控制器:

var categories = _context.ProductCategories.Include(e => e.Children).ToList();
var topLevelCategories = categories.Where(e => e.ParentId == null);
return View(topLevelCategories);

查看:

@if (Model != null)
{
    foreach (var item in Model)
    {
    <li>
        @item.Title
        <ul>
            @Html.Partial("_CategoryRecursive.cshtml", item.Children)
        </ul>
    </li>
    }
}

但是当我尝试将此设置转换为我的viewmodel(并添加用于计算每个类别中的产品的属性,以及没有任何类别连接的产品列表)时......:

视图模型:

public class ViewModelProductCategory
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Title { get; set; }
    public int SortOrder { get; set; }

    public string ProductCountInfo
    {
        get
        {
            return Products != null && Products.Any() ? Products.Count().ToString() : "0";
        }
    }

    public ViewModelProductCategory ParentCategory { get; set; } // Nav.prop. to parent
    public IEnumerable<ViewModelProductCategory> Children { get; set; } // Nav.prop. to children
    public List<ViewModelProduct> Products { get; set; } // Products in this category
    public List<ViewModelProduct> OrphanProducts { get; set; } // Products with no reference in ProductInCategory
}

控制器:

            var VMCategories = _context.ProductCategories
                        .Include(e => e.Children)
                        .OrderBy(s => s.SortOrder)
                        .Where(r => r.ParentId == null) // only need root level categories in the View
                        .Select(v => new ViewModelProductCategory
                        {
                            Id = v.Id,
                            ParentId = v.ParentId,
                            Title = v.Title,
                            SortOrder = v.SortOrder,
                            // get products without a category:
                            OrphanProducts = v.ProductInCategory
                                            .Where(o => !_context.ProductsInCategories.Any(pc => o.Id == pc.ProductId))
                                            .Select(orph => new ViewModelProduct
                                            {
                                                Id = orph.Product.Id,
                                                Title = orph.Product.Title,
                                                Price = orph.Product.Price,
                                                Info = orph.Product.Info,
                                                SortOrder = orph.SortOrder
                                            })
                                            .OrderBy(s => s.SortOrder)
                                            .ToList()

                        })
                        .ToList();
        return View(VMCategories);

查看:

@if (Model != null)
{
    foreach (var item in Model)
    {
    <li>
        @item.Title (@item.ProductCountInfo)
        <ul>
            @Html.Partial("_CategoryRecursive.cshtml", item.Children)
        </ul>
    </li>
    }
}

......它将不再起作用。视图确实呈现,但它只显示根类别。似乎我的修改后的查询不会获得任何子类别。当我检查查询结果时,Children属性为null。

修改

我将使用@ Rainman的解决方案,并将我的查询.Select更改为包含Children = v.Children,,并改变我的viewmodel导航属性:

public ProductCategory ParentCategory { get; set; } //nav.prop to parent
public ICollection<ProductCategory> Children { get; set; } //nav. prop to children

我还创建了新的viewmodel CategoryRecursiveModel并将我的观点改为:

@model IEnumerable<MyStore.Models.ViewModels.ViewModelProductCategory>

<ul>
@if (Model != null)
{
    foreach (var item in Model)
    {
        <li>
            @item.Title (@item.ProductCountInfo)
            <ul>
                @Html.Partial("_CategoryRecursive.cshtml", new CategoryRecursiveModel
                {
                    Children = item.Children.ToList();
                })
            </ul>
        </li>
    }
}
</ul>

现在我遇到了InvalidOperationException,因为视图期望有一个IEnumerable的ViewModelProductCategory,但是接收到了CategoryRecursiveModel。

1 个答案:

答案 0 :(得分:0)

因为您没有为第二个查询选择Children;

var VMCategories = _context.ProductCategories
    .Include(e => e.Children)
    .OrderBy(s => s.SortOrder)
    .Where(r => r.ParentId == null) // only need root level categories in the View
    .Select(v => new ViewModelProductCategory
    {
        Id = v.Id,
        Children = v.Children, // Select it
        ParentId = v.ParentId,
        Title = v.Title,
        SortOrder = v.SortOrder,
        // get products without a category:
        OrphanProducts = v.ProductInCategory
            .Where(o => !_context.ProductsInCategories.Any(pc => o.Id == pc.ProductId))
            .Select(orph => new ViewModelProduct
            {
                Id = orph.Product.Id,
                Title = orph.Product.Title,
                Price = orph.Product.Price,
                Info = orph.Product.Info,
                SortOrder = orph.SortOrder
            })
            .OrderBy(s => s.SortOrder)
            .ToList()

    })
    .ToList();
public ProductCategory ParentCategory { get; set; } //nav.prop to parent
public ICollection<ProductCategory> Children { get; set; } //nav. prop to children

此外,导航属性仅适用于非ViewModelProductCategory模型类或其他类的EF实体。

修改

_CategoryRecursive视图创建模型类;

public class CategoryRecursiveModel
{
    public List<ProductCategory> Children { get; set; }
}

改变主视图;

@if (Model != null)
{
    foreach (var item in Model)
    {
        <li>
            @item.Title (@item.ProductCountInfo)
            <ul>
                @Html.Partial("_CategoryRecursive.cshtml", new CategoryRecursiveModel
                {
                    Children = item.Children.ToList();
                })
            </ul>
        </li>
    }
}