如何将LINQ to SQL Distinct()运算符应用于List

| 我在LINQ to SQL中遇到严重的问题(这使我发疯了)。我正在Visual Studio 2010中使用c#和Razor开发ASP.NET MVC3应用程序。 我有两个数据库表,产品和类别: 产品(Prod_Id [主键],其他属性) 类别((Dept_Id,Prod_Id)[主键],其他属性) 显然,类别中的Prod_Id是外键。这两个类均使用实体框架(EF)进行映射。为了简单起见,我没有提及应用程序的上下文。 在类别中,有多行包含Prod_Id。我想对所有类别中的不同Prod_Id进行投影。我根据以下(非常简单的)查询在SQL Server MGMT Studio中使用普通(T)SQL进行了此操作:
SELECT DISTINCT Prod_Id
FROM Categories
结果是正确的。现在,我需要在应用程序中进行此查询,因此我使用了:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
我使用以下方法检查查询结果:
query.Select(m => m.Prod_Id);
要么
foreach(var item in query)
{
  item.Prod_Id;
  //other instructions
}
它不起作用。首先,当我尝试编写
query.Select(m => m.
item.
时,Intellisense仅显示有关方法的建议(例如Equals等),而不是属性。我以为Intellisense可能有问题(我想大多数人都希望Intellisense是错误的:-D),但是当我启动应用程序时,我在运行时收到错误消息。 在给出答案之前,请记住: 1)我检查了很多论坛,我尝试了普通的LINQ to SQL(不使用lambdas),但是它不起作用。它在(T)SQL中起作用的事实意味着LINQ to SQL指令存在问题(我的应用程序中的其他查询可以正常工作)。 2)由于与应用程序相关的原因,我使用了一个
List<T>
变量而不是_StoreDB.Categories,我认为这就是问题所在。如果您能为我提供不使用ѭ6的解决方案,也将不胜感激。 谢谢你的回答 弗朗切斯科
已邀请:
这行:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
您的LINQ查询最有可能返回
ints
的IEnumerable ...(以
Select(m => m.Prod_Id)
判断)。您具有整数列表,而不是实体对象列表。尝试打印它们,然后看得到什么。
调用
_StoreDB.Categories.Select(m => m.Prod_Id)
意味着
query
将仅包含
Prod_Id
值,而不包含整个实体。这将大致等效于此SQL,该SQL仅选择一列(而不是整个行):
SELECT Prod_Id FROM Categories;
因此,当您使用
foreach (var item in query)
遍历
query
时,
item
的类型可能是
int
(或任何您的
Prod_Id
列),而不是您的实体。这就是为什么Intellisense不显示您键入\“
item.
\”时期望的实体属性的原因... 如果要将want21ѭ中的所有列都包含在
query
中,则甚至不需要使用
.Select(m => m)
。您可以这样做:
var query = _StoreDB.Categories.Distinct();
请注意,如果您未将
IEqualityComparer<T>
显式传递给
Distinct()
,则将使用
EqualityComparer<T>.Default
(取决于
T
的类型,是否实现
System.IEquatable<T>
,其行为可能与您想要的方式不同)。 。 有关使30英镑在与您相似的情况下工作的更多信息,请查看此问题或相关问题以及相关讨论。
正如其他答案所解释的那样,OP遇到的错误是因为他的代码的结果是一个整数集合,而不是一个类别集合。 尚未得到答案的是他的问题,即如何在联接中使用int集合或其他方法以获取一些有用的数据。我将在这里尝试这样做。 现在,我不太确定为什么OP希望从类别中获得不同的Prod_Id列表,而不仅仅是从Projects中获得Prod_Id。也许他想找出与一个或多个类别相关的产品,因此任何未归类的产品都将从结果中排除。我假设是这种情况,并且期望的结果是具有相关类别的不同产品的集合。我将首先回答有关如何处理Prod_Id的问题,然后提供一些替代方法。 我们可以完全按照问题中创建的Prod_Ids的集合进行查询:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
然后,我们将使用join,如下所示:
var products = query.Join(_StoreDB.Products, id => id, p => p.Prod_Id,
               (id,p) => p);
这将获取查询,将其与Products表连接,指定要使用的键,最后说要从每个匹配集中返回Product实体。因为我们知道查询中的Prod_Id是唯一的(因为Distinct()),而产品中的Prod_Ids是唯一的(根据定义,因为它是主键),所以我们知道结果将是唯一的,而不必调用Distinct() 。 现在,以上方法将获得理想的结果,但是绝对不是最干净或最简单的方法。如果使用关联属性定义Category实体,该属性从Products返回相关记录(可能会称为Product),则执行我们要执行的操作的最简单方法如下:
var products = _StoreDB.Categories.Select(c => c.Product).Distinct();
这将从每个类别中获取产品,并返回它们的不同集合。 如果Category实体不具有Product关系属性,那么我们可以返回使用Join函数来获取我们的Products。
var products = _StoreDB.Categories.Join(_StoreDB.Products, c => c.Prod_Id,
               p => p.Prod_Id, (c,p) => p).Distinct();
最后,如果我们不只是想要一个简单的产品集合,那么就必须进行更多的研究,也许最简单的事情是在遍历产品时进行处理。另一个示例是获取每个产品所属类别的数量的计数。如果是这种情况,我将颠倒逻辑并从Products开始,如下所示:
var productsWithCount = _StoreDB.Products.Select(p => new { Product = p,
    NumberOfCategories = _StoreDB.Categories.Count(c => c.Prod_Id == p.Prod_Id)});
这将导致一个匿名类型的对象的集合,这些对象引用该产品以及与该产品相关的NumberOfCategories。如果我们仍然需要排除任何未修饰的产品,则可以在分号前附加ѭ36。当然,如果使用相关类别的关系属性定义了Product实体,则不需要此属性,因为您可以选择任何Product并执行以下操作:
int NumberOfCategories = product.Categories.Count();
无论如何,对不起,您不满意。我希望这对遇到类似问题的其他人有帮助。 ;)

要回复问题请先登录注册