【问题标题】:Dynamic Linq Where IN动态 Linq 在哪里
【发布时间】:2018-04-01 19:16:14
【问题描述】:

如何使用Dynamic Linq 定义where in 条件?

我厌倦了下面的解决方法,但它一定不起作用,因为它没有意义!

context.Records.Where("@0.Contains(ID)", new object[]{
   new string[] {"1", "2", "3"}
}); // throws error No property or field 'ID' exists in type 'String'

编辑 1:

感谢大家,您只需在Dynamic.Linq 查询中使用itouterIt 关键字,所以在我的示例中我只需要使用outerIt

context.Records.Where("@0.Contains(outerIt.ID)", new object[]{
   new string[] {"1", "2", "3"}
});

您可以在此处找到更多示例和信息:Advanced Linq - Dynamic Linq query library: Add support for 'Contains' extension

【问题讨论】:

  • 您在使用 EntityFramework 吗?
  • 你不需要那个。使用context.Records.Where(x => list.Contains(x.ID)
  • @OleksandrNahirniak 是的。
  • @CamiloTerevinto 我需要使用动态 Linq
  • 可以在github.com/StefH/System.Linq.Dynamic.Core找到支持.NET Core的更新版本

标签: c# linq dynamic-linq


【解决方案1】:

这里的其他人介绍了有趣的解决方法,但如果我们使用 Dynamic.Linq 库,它们就没有用了。 Oleksandr Nahirniak found this question on Stackoverflow。还有一篇关于使用 Dynamic.Linq 进行高级 Linq 查询的博客文章,其中评论了here

1.0.4 版本开始,该库也支持Contains 扩展。它可以像下面这样完成:

 query = Contact.GetContactsList()
                .AsQueryable()
                .Where("@0.Contains(outerIt.Country)", new List<String>() { "Austria", "Poland" }); 

query = Contact.GetContactsList()
               .AsQueryable()
               .Where("@0.Contains(outerIt.Country) && it.BirthDate.Year > @1", new List<string>() { "Austria", "Poland" }, 1955);

有两个关键字itouterIt。它代表您作为参数传递的列表,outerIt 代表集合本身。

这是我的工作示例:

context.Records.Where("@0.Contains(outerIt.ID)", new object[]{
   new string[] {"1", "2", "3"}
});

【讨论】:

    【解决方案2】:

    如果您使用 EF,则可以使用直接 sql 命令,例如:

    context.Database.ExecuteSqlCommand($"SELECT * FROM Records AS r WHERE r.{dynamicPropertyName} IN @ids", new string[] {"1", "2", "3"});
    

    编辑

    已解决:

    System.Linq.Dynamic - Can I use IN clause in WHERE statement

    【讨论】:

    • 既然可以使用Contains,为什么还要编写SQL?
    • @CamiloTerevinto 我是如何理解主题启动者的问题的,您不知道(在运行时/动态中)您要申请哪个属性进行 IN 操作。在其他情况下,linq 更可取。
    • 您可以使用动态 LINQ(通过使用几个 Expressions)来做到这一点,而无需手动编写 SQL,这完全违背了使用 EF 的初衷
    • @CamiloTerevinto 哦,是的,有道理,你是对的,谢谢
    • 您提供的链接对我帮助很大。
    【解决方案3】:

    你可以编写自己的扩展方法In,这里是IEnumerable:

    public static class ExtLinq
        {
        public static IEnumerable<TSource> In<TSource, TMember>(this IEnumerable<TSource> source,
                Func<TSource, TMember> identifier, params TMember[] values) =>
             source.Where(m => values.Contains(identifier(m)));
        }
    

    像这样使用它:

    context.Records.In(x => x.ID, 1, 2, 3)
    

    如果您希望在服务器上执行 IN 以节省数据传输,请使用此 IQueryable 版本,使用表达式 API 实现:

    public static IQueryable<TSource> In<TSource, TMember>(this IQueryable<TSource> source,
       Expression<Func<TSource, TMember>> identifier, params TMember[] values)
            {
                var parameter = Expression.Parameter(typeof(TSource), "m");
                var inExpression = GetExpression(parameter, identifier, values);
                var theExpression = Expression.Lambda<Func<TSource, bool>>(inExpression, parameter);
                return source.Where(theExpression);
            }
    static Expression GetExpression<TSource, TMember>(ParameterExpression parameter, Expression<Func<TSource, TMember>> identifier, IEnumerable<TMember> values)
            {
                var memberName = (identifier.Body as MemberExpression).Member.Name;
                var member = Expression.Property(parameter, memberName);
                var valuesConstant = Expression.Constant(values.ToList());
                MethodInfo method = typeof(List<TMember>).GetMethod("Contains");
                Expression call = Expression.Call(valuesConstant, method, member);
                return call;
            }
    

    这个查询(或类似的依赖于您的表)将在服务器上执行并返回所需的数据:

    SELECT
        [Extent1].[ID] AS [ID],
        [Extent1].[Name] AS [Name]
        FROM [dbo].[Records] AS [Extent1]
        WHERE [Extent1].[ID] IN (1, 2, 3)
    

    【讨论】:

      【解决方案4】:

      您可以通过创建一个简单的扩展方法来轻松获得相同的结果,如下所示:

      public static class Utils
      {
          public static bool In<T>(this T src, params T[] items)
          {
              return items.Contains(src);
          }
      }
      

      然后这样称呼它:

      context.Records.Where(record => record.In("1", "2", "3"));
      

      【讨论】:

      • 没错,但我使用的是Dynamic.Linq库,所以我不能使用上面的解决方法。
      猜你喜欢
      • 2012-12-02
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 2016-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多