1

我现在已经为一个简单的问题摆弄了整整两天。

我有一个包含 Product 实体和 ProductLocationHistory 实体的数据库。ProductLocationHistory 具有对 Storehouse、Contact 或 Relation 的引用。每次移动产品时,它都会获得一个新条目,因此可以追踪产品的过去。因此,当前位置是由 ProductLocationHistory 的 DateCreation 字段确定的最后一个条目。

一个例子:

var storehousesWithBorrowedItems = productService.GetAllProducts()
    .Select(p => p.ProductLocationHistories
        .SingleOrDefault(plh => plh.DateCreation == p.ProductLocationHistories.Max(grp => grp.DateCreation)))
    .Select(plh => plh.Storehouse)
    .Distinct();

这些都是目前有产品的仓库。

当然,在我需要确定产品的当前位置时,将其写在代码中是非常不方便的。由于可能存在一致性问题,我认为完全不希望引用 Product 中的当前 ProductLocationHistory。我更喜欢这样的东西:

Product.ProductLocationHistories.Current();

所以我尝试了:

public static ProductLocationHistory Current(this EntitySet<ProductLocationHistory> plhs)
    {
        return plhs.SingleOrDefault(plh => plh.DateCreation == plhs.Max(grp => grp.DateCreation));
    }

这不适用于可查询,因为我得到“当前不支持对 sql 的翻译”,并且由于 Product 和 ProductLocationHistory 的组合通常是查询的“开始”,我想保持 IQueryable 而不是立即到 IEnumerable 并进行查询为每个产品确定当前位置!更不用说之后的其他内容了......经常使用任何实体的当前日志条目,只要 .Current() 函数工作并保持可查询,它的复杂程度并不重要。我曾希望我的 .Current(...) 函数能够工作,因为底层代码是可查询的,但我仍然遇到异常。当代码像第一个示例中那样内联时,我没有得到异常。

我已经经历了诸如 Func、ProductLocationHistory>> 以及 Expression<...> 之类的可能性,但我找不到我正在寻找的示例。Product.CurrentProductLocationHistory() 类型的解决方案可能会更好。绝对最佳的解决方案将更加通用,形式如下:

Current<T> (IQueryable<T> collection, string field) { return entity with max field of collection } 

非常感谢您的帮助,我已经尝试了很长时间,并且我确信它必须是可能的,因为 LINQ 本身的内部功能 - Any,First,Count,Max - 如果需要也可以查询。

更新

目前,以下工作:

 Expression<Func<Product, ProductLocationHistory>> expression = IQueryable.Current(null);
        var ken = productService.GetAllProducts()
            .Where(p => p.OnLoan)
            .Select(expression)
            .Where(plh => plh.Storehouse != null)
            .Select(plh => plh.Storehouse)
            .Distinct();

public static Expression<Func<Product, ProductLocationHistory>> Current(this EntitySet<ProductLocationHistory> productLocationHistories)
    {
        Expression<Func<Product, ProductLocationHistory>> expression = p => p.ProductLocationHistories
                                         .SingleOrDefault(plh => plh.DateCreation == p.ProductLocationHistories.Max(plhs => plhs.DateCreation));
        return expression;
    }

朝着正确的方向迈出了一步,但我还没有完全满意。我希望能够使用 p.ProductLocationHistories().Current() 所以我的任务继续。

已经感谢基里尔了!这是我第一次看到 C# 代码翻译成 SQL!朝着正确方向迈出的一大步!

4

1 回答 1

1

您可以使用表达式设置字段:

Expression<Func<ProductLocationHistory, bool>> currentSelector = plh => plh.DateCreation == p.ProductLocationHistories.Max(grp => grp.DateCreation)

并在任何地方使用它:

var storehousesWithBorrowedItems = productService.GetAllProducts()
    .Select(p => p.ProductLocationHistories
        .SingleOrDefault(currentSelector ))
    .Select(plh => plh.Storehouse)
    .Distinct();
于 2012-11-17T08:08:45.023 回答