【问题标题】:LINQ: "Enumeration yielded no results"LINQ:“枚举没有结果”
【发布时间】:2016-01-01 23:31:59
【问题描述】:

我在尝试让 LINQ 语句正常工作时遇到了麻烦。

我在这篇文章之后尝试使用 SQL 语法和 lambda:

C# Joins/Where with Linq and Lambda

这是我的工作 SQL 的样子:

SELECT ws_lookup_OccupationGroup.Code
FROM ws_lookup_OccupationGroup
INNER JOIN ws_lookup_Occupation ON
ws_lookup_OccupationGroup.Code = ws_lookup_Occupation.ws_lookup_OccupationGroup_Code
WHERE (ws_lookup_Occupation.Code = N'413')

这是我的第一次尝试,它没有产生任何结果:

var query = from occupationGroup in db.ws_lookup_OccupationGroups 
            join occupations in db.ws_lookup_Occupations on occupationGroup.Code equals occupations.Code 
            where occupations.Code == model.Client.Client_Details_Enhanced.Occupation.Code 
            select new 
            { 
                OccupationGroup = occupationGroup, 
                Occupations = occupations 
            };

这是我使用 Lamdba 的第二次尝试,但也没有产生任何结果:

var queryLambda = db.ws_lookup_OccupationGroups
                    .Join(db.ws_lookup_Occupations, 
                          occupation => occupation.Code, 
                          occupationGroup => occupationGroup.Code,
                          (occupation, occupationGroup) => new 
                          { 
                              OCCUPATION = occupation, 
                              OCCUPATIONGROUP = occupationGroup 
                          })
                    .Where(all => all.OCCUPATION.Code == model.Client.Client_Details_Enhanced.Occupation.Code);

我只是看不到出了什么问题......

我不知道这是否有任何相关性,但我使用的是 Code First Entity Framework - 他是我的 OccupationGroups & Occupations 模型:

public class ws_lookup_OccupationGroup {
    [Key]
    [MaxLength(250)]
    public string Code { get; set; }
    [MaxLength(250)]
    public string Name { get; set; }
    public int SortOrder { get; set; }
    public List<ws_lookup_Occupation> Occupations { get; set; }
}
public class ws_lookup_Occupation {
    [Key]
    [MaxLength(10)]
    public string Code { get; set; }
    [MaxLength(250)]
    public string Name { get; set; }
    [MaxLength(250)]
    public string BarbadosMotorFactor { get; set; }
    [MaxLength(250)]
    public string TrinidadMotorFactor { get; set; }
    [MaxLength(250)]
    public string OtherRegionsMotorFactor { get; set; }
}

【问题讨论】:

  • 您是否尝试过硬编码值为 413 而不是 model.Client.Client_Details_Enhanced.Occupation.Code 的语句?
  • 刚刚尝试过 - 也没有产生任何结果:(
  • 您的查询的两个版本看起来都正确。您是否分析过数据库以查看实际发出的 SQL 是什么?
  • LINQPad 对于调试这样的查询很有用,您可以像在 Management Studio 中一样快速编辑查询。
  • 在 SQL 中,您加入 ws_lookup_Occupation.ws_lookup_OccupationGroup_Code,但在 Linq 中,您加入 occupations.Code。但实际上你应该只使用navigation properties 而不是加入。

标签: c# linq


【解决方案1】:

在您的 SQL 中,您将加入以下内容

ws_lookup_OccupationGroup.Code = ws_lookup_Occupation.ws_lookup_OccupationGroup_Code

但是在 Linq 中你加入了

occupationGroup.Code equals occupations.Code

根据您的实体的具体外观,我会假设您确实需要这个

occupationGroup.Code = occupations.ws_lookup_OccupationGroup_Code

根据您的实体,您似乎可以使用导航属性而不是连接来执行以下操作

var query = from occupationGroup in db.ws_lookup_OccupationGroups 
            where occupationGroup.Occupations.Any(
                o => o.Code == model.Client.Client_Details_Enhanced.Occupation.Code) 
            select occupationGroup;

获取所有至少具有所需代码的职业的职业组。或者,如果您只是想要团体和职业的组合,那么您可以这样做

var query = from occupationGroup in db.ws_lookup_OccupationGroups 
            from occupation in occupationGroup.Occupations
            where occupation.Code == model.Client.Client_Details_Enhanced.Occupation.Code
            select new 
            {
                occupationGroup,
                occupation
            };

【讨论】:

  • 我不知道正确的连接语法应该是什么——我对 linq 很陌生——你能帮忙解决一下语法吗?
  • @TrevorDaniel 查看我的更新。您只需要使用对应于相同列的属性(它们通常具有相同的名称)。
  • occupations.ws_lookup_OccupationGroup_Code 不可见 - 只有一个列表 - 我已经用我的模型更新了我的问题......我仍然很难过。
  • @TrevorDaniel 我已经用使用您的导航属性的查询更新了我的答案。你必须准确地确定你想要什么来决定你应该如何使用它们。
  • 你是我的英雄! - 我欠你几杯啤酒 :)
【解决方案2】:

与其直接回答您的问题,我更愿意提出策略建议。然后一种策略是添加一个扩展方法,该方法将显示您的实体框架查询或 IQueryable 将运行的 SQL。这可以通过创建单元测试并执行测试驱动开发方法或 TDD 的方式来完成。

您知道要获得预期结果的 SQL。然后最好使用您的 EF 查询,直到您获得将提供您所追求的结果的 SQL。您可以调试集成测试,然后朝着最终结果前进 - 您所追求的 SQL - 用 Entity Framework Linq to Entities 代码编写。

首先,我们可以创建如下扩展方法:

public static class IQueryableExtensions
    {

        /// <summary>
        /// Shows the sql the IQueryable query will be generated into and executed on the DbServer
        /// </summary>
        /// <param name="query">The IQueryable to analyze</param>
        /// <param name="decodeParameters">Set to true if this method should try decoding the parameters</param>
        /// <remarks>This is the generated SQL query in use for Entity Framework</remarks>
        public static string ShowSql(this IQueryable query, bool decodeParameters = false)
        {
            var objectQuery = (ObjectQuery)query; 

            string result = ((ObjectQuery)query).ToTraceString();

            if (!decodeParameters)
                return result; 

            foreach (var p in objectQuery.Parameters)
            {
                string valueString = p.Value != null ? p.Value.ToString() : string.Empty;
                if (p.ParameterType == typeof(string) || p.ParameterType == typeof(DateTime))
                    valueString = "'" + valueString + "'";
                result = result.Replace("@" +p.Name, p.Value != null ? valueString : string.Empty); 
            }
            return result; 
        }     

}

然后我们需要一些集成测试,来自我自己的系统的示例:

  [TestFixture]
    public class IqueryableExtensionsTest
    {

        [Test]
        public void QueryableReturnsSqlAndDoesNotThrow()
        {
            using (var dbContext = ObjectContextManager.ScopedOpPlanDataContext)
            {
                var operations = from operation in dbContext.Operations
                    where operation.Status == (int) OperationStatusDataContract.Postponed
                    && operation.OperatingDate >= new DateTime(2015, 2, 12)
                    select operation;
                string sql = operations.ShowSql();
                Assert.IsNotNull(sql);
            }
        }

    }

虽然您当然可以使用 Linqpad 来查找您所追求的 EF 查询和 SQL,但这种策略的好处是您可以在 Visual Studio 中将它用于更复杂的现实世界场景,您还可以获得更好的调试体验胜过在 VS 和 Linqpad 之间切换。

如果您调试此类集成测试,则可以观察生成的 SQL。请注意,如果您想运行集成测试而不是调试它,也可以执行 Console.WriteLineDebug.WriteLine 来观察输出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多