【问题标题】:LINQ to SQLLINQ 到 SQL
【发布时间】:2009-01-01 02:55:13
【问题描述】:

我正在完成一个 C# ASP.NET 程序,它允许用户通过从下拉列表中选择硬件组件(如内存、cpu 等)来构建自己的计算机。 SQL 数据表有 3 列;计算机 ID、属性和值。 computerID是我的产品主数据表中与某台计算机对应的ID,Attribtute是硬件组件的名称;内存、cpu、硬盘等。值是分配给该属性的值,例如 1GB 或 2.8GHz 320GB。这意味着一台计算机将具有多个属性。

我试图通过首先选择满足第一个属性要求的所有计算机然后从该列表中获取所有满足下一个要求的计算机来缩小结果范围......等等大约 10 多个属性。

我认为向您展示我的 LINQ to SQL 查询示例可能是个好主意,这样您就可以更好地了解我想要做什么。这基本上选择了计算机内存大于1GB的ComputerID。

var resultsList = from results in db.ComputerAttributes
                  where computer.Value == "MEMORY" && computer.Value >= "1"
                  select results.ComputerID;

接下来我想从结果列表中选择 CPU 所在的位置,比 2.8Ghz 快,等等。

我希望我已经为您提供了足够的信息。 如果有人可以就如何完成这个很棒的项目给我一些建议。

谢谢

【问题讨论】:

    标签: sql sql-server linq


    【解决方案1】:

    您需要使用 Concat 作为“Union All”。

    IQueryable<ComputerAttribute> results = null;
    foreach(ComputerRequirement z in requirements)
    {
      //must assign to a locally scoped variable to avoid using
      //  the same reference in all of the where methods.
      ComputerRequirement cr = z;
      if (results == null)
      {
        results = db.ComputerAttributes
          .Where(c => c.Attribute == cr.Attribute && c.Value >= cr.Value);
      }
      else
      {
        results = results
          .Concat(db.ComputerAttributes
             .Where(c => c.Attribute == cr.Attribute && c.Value >= cr.Value)
          );
      }
    }
    
    int requirementCount = requirements.Count();
    
    //Get the id's of computers that matched all requirements.
    IQueryable<int> ids = results
      .GroupBy(x => x.ComputerId)
      .Where(g => g.Count == requirementsCount)
      .Select(g => g.Key);
    
    
    //Get all attributes for those id's
    List<ComputerAttributes> data = db
      .ComputerAttributes.Where(c => ids.Contains(c.ComputerId))
      .ToList();
    

    【讨论】:

      【解决方案2】:

      我假设你在问:

      如何优化使用 LINQ to SQL 完成的搜索内容?

      还是类似的吧?

      据我了解,您有两种选择:

      1. 过滤内存中的结果(如果已缓存)。
      2. 扩展您的 SQL 查询并再次访问数据库。

      我不确定 LINQ to SQL 是否允许您重新查询现有结果集。我很确定它不会。

      【讨论】:

        【解决方案3】:

        您可能想改用扩展方法。将这些链接在一起可能会更容易一些。此外,您将无法对字符串进行小于/大于比较,因为 SQL 不支持这些类型的字符串比较。但是,如果您存储的 id 与字符串描述具有相同的顺序,则可以比较它们。

        使用扩展方法,您可以执行以下操作:

        Dictionary<string,int>  attributeMap = new Dictionary<string,int>();
        attributeMap.Add("MEMORY",1000);
        attributeMap.Add("SPEED",2800);
        
        var results = db.ComputerAttributes;
        foreach (var attribute in attributeMap)
        {
            results = results.Where( c => c.Attribute == attribute.Key
                                     && c.Value >= attribute.Value );
        }
        
        var ids = results.Select( c => c.ComputerID );
        
        foreach (int id in ids)
        {
            ...
        }
        

        在上面的例子中,1000 相当于 1GB,2800 相当于 2.8GHz。

        【讨论】:

        • 我同意这种技术。特别是切换到扩展方法。我喜欢扩展方法而不是表达式语法的部分原因是我不想学习两种编写“SQL”的方法。加上扩展方法链接的想法非常方便。
        • 所以,第一次通过循环...我们将过滤到内存属性。第二次我们将根据速度要求过滤这些内存属性,我们将得到 0 个匹配项。
        • 还有一些问题。 “var results”会将结果键入为表格,而不是 IQueryable。而且,直接在过滤器中使用循环变量会导致测试最后一个需求而不是其他需求的内部错误。
        【解决方案4】:

        哇,谢谢大家的建议,它非常有用。我会试试你的方法,告诉你事情的进展。 David B 的最后一个解决方案与我之前所做的非常相似(计算 ComputerID 的出现次数),但是我的代码效率极低。 :)

                string[] FinalResults = new string[100];
                int Counter2 = 0;
                foreach (string Result in Results)
                {
                    string test = Result;
                    var Counter1 = 0;
                    foreach (string Result2 in Results)
                    {
                        if (test == Result2)
                        {
                            Counter1++;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    if (Counter1 >= 3 && Result != null)
                    {
                        FinalResults.SetValue(Result,Convert.ToInt32(Counter2));
                    }
                    else
                    {
                        continue;
                    }
                    Counter2++;
                }
                foreach (string FinalResult in FinalResults)
                {
                    if (FinalResult != null)
                    {
                        Response.Write("Laptop: " + FinalResult + "<br />");
                    }
                    else
                    {
                        continue;
                    }
                }
            }
        

        在我尝试过每个答案后会选择最佳答案。再次感谢大家的帮助,它已经挽救了生命。

        【讨论】:

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