【问题标题】:Entity Framework - LINQ - Dynamic Column Names实体框架 - LINQ - 动态列名
【发布时间】:2018-10-11 10:17:43
【问题描述】:

我知道这个问题被问了好几次,但我得到的答案越多,我就越困惑。

鉴于我有一个表 Categories 并且在此表列中:Category1Category2Category3 等等。我如何编写如下所示的方法并使用参数(在这种情况下为 @ 987654325@)

尽可能简化;

public List<string> GetProductCategories(int catno)
{
    using (var ctx = new myEntities())
    {
        return (from c in ctx.Categories
                select c.Category1).ToList();
               //1 being the catno parameter obviously
    }
}

我绝对想使用 Dynamic Linq 库,因为它不是类型安全的。虽然(显然)一个可行的答案会很好,但提供了对问题和解决方案的详细解释。

提前致谢

【问题讨论】:

    标签: c# linq lambda entity-framework-6


    【解决方案1】:

    如果你想要完整的类型安全,除了使用 switch case 将整数映射到其相应的类别之外,我没有看到任何其他方法:

    public List<string> GetProductCategories(int catno)
    {
        using (var ctx = new myEntities())
        {
            switch (catno)
            {
                case 1:
                    return ctx.Categories.Select(c => c.Category1).ToList();
                case 2:
                    return ctx.Categories.Select(c => c.Category2).ToList();
                default:
                    throw new ArgumentException("Category number not supported!");
            }
        }
    }
    

    您显然可以做的另一件事是重构您的代码,以便您拥有包含字符串属性和数字的 Category 类列表,然后您可以编写如下内容:

    return ctx.Categories.Where(c => c.CategoryNumber == catno)
        .Select(c => c.CategoryDescription)
        .ToList();
    

    我认为您可能应该重构您的代码。当我看到“Category1”和“Category2”时,我闻到了糟糕的设计,听起来这些应该是类别列表中的项目。

    还有关于 Dynamic Linq 的评论,例如,如果您收到来自您无法控制的客户端的请求,则使用动态 linq 没有任何问题。如果没有找到该属性,您可以简单地返回一个错误。

    【讨论】:

    • 非常感谢您的回答。同意糟糕的设计,虽然它不属于我,但是这种情况可能会在不同的情况下出现,所以很高兴知道可能的解决方法。此外,虽然映射听起来是个好主意,但在某些情况下(例如 db 视图)也可能会自动生成列。您关于重构的第二个建议,我会尝试。这种方法对我来说很新。至于动态 LINQ,我在一定程度上同意你的看法。但话又说回来,如果我觉得自己在那一点上,我可能会改用纯 SQL!
    【解决方案2】:

    您可以定义基于字符串名称选择属性的表达式。然后在IQueryable 接口中,您可以在Select 参数中使用它。不过,您需要使用方法语法:

    public List<string> GetProductCategories(int catno)
    {
        var parameter = Expression.Parameter(typeof(Category));
        var property = Expression.Property(parameter, $"Category{catno}");
        var selector = Expression.Lambda<Func<Category, string>>(property, parameter);
    
        using (var ctx = new myEntities())
        {
            return ctx.Categories
                .Select(selector)
                .ToList();
        }
    }
    

    Expression.Property 方法正在执行一些类型检查,因此如果在类型 Category 上没有定义给定属性,它将引发异常。例如,如果没有 Category0 属性,这将失败:

    var property = Expression.Property(parameter, "Category0");
    

    【讨论】:

    • 我建议不要手动编写表达式,它们可能不会以您期望的方式运行,并且可能会导致一些问题。相反,只需使用Dynamic LINQ Library,它允许您编写如下查询:list.OrderBy("Category ASC") 以升序排序。
    • 感谢 Shahin,我明确提到出于各种原因我不想使用 Dynamic LINQ。好吧,除此之外,表达式可能会出现什么问题?记下来真的很好,因为我不知道。谢谢..
    • @KemalEmin @ShahinDohan Expression API 是安全的(它检查类型等),它是内置库而不是第三方,如 Dynamic LINQ(并且此类库可能不稳定)。它的创建是为了简化生成 IL 代码,因此不需要 IL 知识,还可以将代码表示为数据类型,以便您可以轻松地将其更改为另一种形式,例如SQL。所有的 IQueryable LINQ 和 EF 都基于它。我从来没有遇到过任何问题。
    • 编写表达式与使用库一样动态,但编写该库的人可能知道他们在做什么。你选择什么取决于你,但根据我的经验,编写表达式,尤其是有用和可重用的表达式,很难、很容易破坏和难以维护。我们甚至遇到了一些与它们相关的内存泄漏问题,所以我们最终放弃了整个事情。
    • @ShahinDohan 这是编程中更高级的概念,当某人的熟练程度足够高时,他们可以毫无问题地正确编写这样的表达式是没有问题的。上面的代码非常简单,它与Expression&lt;Func&lt;Category, string&gt;&gt; selector = c =&gt; c.Category1catno = 1 相同,这意味着它将使用Expression API 降低为相同的代码。我不相信任何人都会对此有任何问题。
    【解决方案3】:
    public List<string> GetProductCategories(int catno)
    {
        string catName = string.Format("Category{0}", catno);
        using (var ctx = new myEntities())
        {
            var result = ctx.Categories.Select(x => {
                    var prop = x.GetType().GetProperty(catName);
                    if (prop == null)
                    {
                        return double.NaN;
                    }
                    return double.Parse(prop.GetValue(x).ToString());
                }).ToList();
            return result.Where(x => !double.IsNaN(x)).ToList();
        }
    }
    

    【讨论】:

    • 干得好!恭喜您在 StackOverflow 网络上添加了您的第一个答案。我建议编辑您的答案以解释您的方法以及您的代码在做什么。
    猜你喜欢
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 2017-01-13
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    相关资源
    最近更新 更多