【问题标题】:Join LINQ-query with predicate使用谓词加入 LINQ 查询
【发布时间】:2016-09-30 07:16:53
【问题描述】:

我在 C# 中使用 LINQ 查询时遇到了一些问题。

我在数据库中有相同结构的相同表。 所以,今天,我的 LINQ 查询遇到了麻烦。

更多细节,我想使用谓词连接一些表。

我有一个有两个参数的函数。 第一个参数是某种Context(比如ProductContext、CarContext、CatContext等)。

第二个参数是List<something>,我将与我的第一个参数 - 上下文一起加入。

我不想要一组方法。

我已添加示例:

    public Element[] GetByIds( MyPredicateContext, Guid[] ids)
    {
        return 
            from id in ids
            join element in MyPredicateContext on id equals element.Id
            select
                new Element
                {
                    Id = element.Id,
                    Description = element.JobDescription,
                };
    }

【问题讨论】:

  • 为什么你想要一个上下文作为参数,而不是一个表?或者你想要两者?而且我猜你所有的元素都没有JobDescription 属性,是吗?

标签: c# .net linq linq-to-sql


【解决方案1】:

如果查询正确,我可以看到的一个基本问题是返回类型是元素数组,而您试图返回 IEnumerable。也许对结果集执行 .ToArray() 可能会解决问题。

【讨论】:

  • 这个问题没关系
  • 抱歉,也许我没有在这里找到问题,请您进一步解释您遇到的确切错误。
  • 对不起,如果您指的是.net Predicate,它们不适合在这里使用。 Filip 给出了一个很好的解决方案,这可能是一个好的开始。我将在 Car、Product 和 Cat 表之间定义一个通用接口并传递该接口,而不是像 Filip 建议的那样传递 MyPredicateContext。请注意,您的 3 个表必须继承自该通用接口。这样,您可以将其中一个表的引用传递给 Filip 提供的方法。
【解决方案2】:

为什么不

return MyPredicateContext.Where(element=>ids.Contains(element.Id))
          .Select(e=>new Element()
             {
                 Id = element.Id, 
                 Description = element.JobDescription
             }).ToArray();

【讨论】:

  • 注意,有join
【解决方案3】:

首先,您不能从数组创建新的 IQueryable,这将恢复为将所有内容拉入内存并在那里过滤。当您使用 SQL 执行 LINQ 时,您使用的是表达式而不是 c# 代码,这仅适用于内存内容(IEnumerable)。 如果您这样做,您的查询将在 SQL 中运行

from element in MyPredicateContext
where ids.Contains(element.Id)
select  new Element
                {
                    Id = element.Id,
                    Description = element.JobDescription,
                }

鉴于 IQueryable 的类型,其中 T 是接口或类。 end 方法看起来像这样

public interface IElement
        {
            Guid Id { get; }
            string JobDescription { get; }
        }

        public Element[] GetByIds<T>(IQueryable<T> myPredicateContext, Guid[] ids) where T:IElement
        {
            return (from element in myPredicateContext
                    where ids.Contains(element.Id)
                    select new Element
                                    {
                                        Id = element.Id,
                                        Description = element.JobDescription,
                                    }).ToArray();

        }

有一些方法可以在没有泛型的情况下做到这一点,但它们更高级一些,并且难以维护。

这是一种适用于所有 T 类型的方法,并且正确的 IQueryable 将产生良好的 sql,正如我指出的那样更高级,您需要查找表达式的工作方式。

public static Element[] GetById<T, Tkey>(IQueryable<T> items,Tkey[] ids)
        {
            var type = typeof(T);
            ParameterExpression param = Expression.Parameter(type);
            var list = Expression.Constant(ids);
            //The names of the properties you need to get if all models have them and are named the same and are the same type this will work
            var idProp = Expression.Property(param, "Id");
            var descriptionProp = Expression.Property(param, "JobDescription");

            var contains = typeof(Enumerable).GetMethods().First(m => m.Name == "Contains" && m.GetParameters().Count() == 2).MakeGenericMethod(typeof(Tkey));
            var where = Expression.Lambda<Func<T, bool>>(Expression.Call(contains, list, idProp), param);

            return (items.
                Where(where).
                Select(Expression.Lambda<Func<T, Element>>(
                    Expression.MemberInit(
                    Expression.New(typeof(Element)),
                        Expression.Bind(typeof(Element).GetProperty("Id"), idProp),
                        Expression.Bind(typeof(Element).GetProperty("Description"), descriptionProp)), 
                        param))).ToArray();
        }

致电GetById(items, new Guid[] { Guid.NewGuid() })

【讨论】:

  • 注意,有加入
  • @Andrew Contains 在这种情况下与您的加入相同。
  • @Filip Cordas。好吧,对不起,这是我的错误,但是如何从 IElement 继承来自 DataBase 的类?
  • Linq sql -- 区域参数 FIRST DECLARE @p0 NVarChar(1000) = '1' DECLARE @p1 NVarChar(1000) = '2' -- EndRegion SELECT [t0].[CODE], [t0].[DESCRIPTION], [t0].[DISPLAYINDEX], [t0].[FILTER] FROM [BCPACTIVITYPLANRISK] AS [t0] WHERE [t0].[CODE] IN (@p0, @p1) GO Second SELECT [t0].[CODE], [t0].[DESCRIPTION], [t0].[DISPLAYINDEX], [t0].[FILTER] FROM [BCPACTIVITYPLANRISK] AS [t0]
  • 如果你的 DataBase 类有两个属性,你的数据模型需要有 Id 属性和 JobDescription 属性,你可以将它用作 T
猜你喜欢
  • 2010-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 2017-10-03
相关资源
最近更新 更多