【问题标题】:SQL double 'IN' clause in lambda expression [duplicate]lambda表达式中的SQL双'IN'子句[重复]
【发布时间】:2017-04-19 15:50:10
【问题描述】:

我有一个带有两个主键的表(和 Dto):intstring 类型:

public class Foo
{
    public int Id { get; set; }
    public string Data { get; set; }

    // other members...
}

所以,我有一个List<Dto> dtoList,它是从一个 DbContext 中获得的。我需要在其他 DbContext 中获得相同的 dto。问题是 PK 是一对两列。

我是这样做的(似乎它不起作用):

public IEnumerable<FooDto> GetFooByPrimaryKeys(List<int> ids, List<string> data)
{
    return FooContext.Foo.Where(f => ids.Contains(f.Id) && data.Contains(f.Data));
}

但它会返回我需要的更多行。我的意思是,我通过了 1300 多对并获得了 1500 多 dto,所以有些不对劲。

我不确定我是否采取了正确的方法。

【问题讨论】:

  • The problem is that the PK is a pair of two columns. - 如果这与您的问题有关,您能否对此进行扩展以及为什么会出现问题?您的解决方案如何解决这个问题?
  • 我想知道这是否可行var compound = ids.Zip(data, (i,d) =&gt; new{Id = i, Data=d}).ToList(); return FooContext.Foo.Where(f =&gt; compound.Contains(new{f.Id, f.Data}));
  • 虽然问题很明显,但考虑到您传入的列表的大小,如果不编写自己的 Sql,我看不到一个简单的解决方法。问题是您正在对任一列表进行 OR 匹配当您应该对元组(一组键)进行 AND 操作时。我不确定是否可以将其转换为 EF 存储查询而无需编写一些手动 sql。
  • 事情是你不能轻易地用 EF 做到这一点,因为你需要一个连接,你不能只连接 EF 中的内存结构。

标签: c# sql .net entity-framework lambda


【解决方案1】:

您需要将ints 和strings 的唯一 传递给该方法。您可以传入一个带有元组的列表,而不是传入两个单独的列表:

public IEnumerable<FooDto> GetFooByPrimaryKeys(List<Tuple<int, string>> keys)
{
    return FooContext.Foo.Where(f => keys.Any(x => x.Item1 == f.Id && x.Item2 == f.Data));
}

如果 Entity Framework 无法处理此问题,您可以选择获取所有记录,然后过滤已实现记录的内存列表:

public IEnumerable<FooDto> GetFooByPrimaryKeys(List<Tuple<int, string>> keys)
{
    return FooContext.Foo.ToList().Where(f => keys.Any(x => x.Item1 == f.Id && x.Item2 == f.Data));
}

如果您有很多记录,您可能需要考虑编写存储过程:

How to pass an array into a SQL Server stored procedure

Passing an array/table to stored procedure through Entity Framework

无论如何,这里的主要问题是您需要与 个值进行比较。

【讨论】:

  • 当我读到这篇文章时我也在想同样的事情,但这是否正确地转换为 EF 的正确数据存储表达式?
  • 这会被EF转换成有效的sql查询吗?我对此表示怀疑。
  • 查看我编辑的答案。
  • 很遗憾我不会写 SP,但我会尝试其他两种解决方案。我认为获取所有项目并在内存中进行“数学运算”并不是那种床主意
  • @MarkC.什么?我还没有标记任何答案,你是什么意思?
【解决方案2】:

您方法中的参数似乎没有将您的复合键视为复合键。

GetFooByPrimaryKeys(List&lt;Tuple&lt;int, string&gt;&gt; ids){ ... }

这将为您提供您正在寻找的密钥对。

然后.Where(f =&gt; ids.Contains(new Tuple&lt;int, string&gt; (f.Id, f.Data)))...

注意:我没有尝试过这段代码,不确定它是否与 EF 的 lambda 引擎兼容。可能是一个很好的起点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    相关资源
    最近更新 更多