从LINQ查询获取不同的行 [英] Getting Distinct Rows from a LINQ Query

查看:44
本文介绍了从LINQ查询获取不同的行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经发布了一个问题,为什么Entity建模者在这里坚持使用一个唯一的密钥; http://social.msdn.microsoft.com/Forums/en-GB/adodotnetentityframework/thread/bde61fbf-2038-4ed3-a1f6-c5cfa2d3ae42


但是我对一个查询有困难这提示了这个问题。


 


基本上我有以下SQL Server存储过程


  ;

 ALTER PROCEDURE [dbo]。[STGP_GetProductInteractionsBySearchText] 
- 在这里添加存储过程的参数
@ProductID int,
@SearchText varchar(100)=''
AS
BEGIN
SELECT iProductID
,iInteractionSeverityID
,sInteractionSeverityText
,FormattedInteractionMessage
,sOtherDrugInteractionText
,iClinicalSetID
,iInteractionGroupID1
,iInteractionGroupID2
,iInteractionMessageID
,iInteractionMessageStyleID
,sInteractionText
,sInteractionMessageStyleText
, sInteractionMessageText
,iOtherDrugProductID
,sOtherDrugDisplayName
,iOtherDrugClinicalSetID
FROM STGV_ProductInteractions
WHERE(iProductID = @ProductID)
AND(sOtherDrugDisplayName LIKE'%'+ @ SearchText +'%')

结束

 


现在,如果我将产品ID 1015729和"paracetamol"一词传递给我,那么我得到20个结果返回;




















1015729 3 通常避免组合。仅在特殊情况下使用组合,采取任何必要措施以降低风险。   增加出血风险 ASPIRIN / SODIUM SALICYLATE 2315 141 26 19 3 NSAIDS


这是因为有20种产品提供相同的互动。


 


然而,我的用户不需要看到所有这些。他们只想看到












3 通常避免组合。仅在特殊情况下使用组合,采取任何必要措施降低风险。 增加出血风险 ASPIRIN / SODIUM SALICYLATE


这将删除为实体提供唯一密钥的productId建模者。


所以我的网页服务返回用户想要的集合如下;


公共列表< ProductInteractionSummary> GetProductInteractionsSummary(int ProductId,String searchText)
{
List< ProductInteractionSummary> list = null;
STGMDDFFormularyEntities ctx = null;

尝试
{
ctx = new STGMDDFFormularyEntities();

var qry = from c in ctx.STGP_GetProductInteractionsBySearchText(ProductId,searchText)
select new ProductInteractionSummary()
{
InteractionSeverityId =(int)i.iInteractionSeverityID,
ExistingDrugInteractionText = i.sOtherDrugInteractionText,
FormattedInteractionMessage = i.FormattedInteractionMessage,
InteractionSeverityText = i.sInteractionSeverityText
};

list = qry.ToList< ProductInteractionSummary>();


}
catch(System.Exception ex)
{
throw ex;
}


返回清单;
}


这会返回一个只包含我需要的属性的列表。但它仍然有20条记录。


 


我尝试了各种形式的区别


  ;


例如围绕括号中的linq查询并在之后放置Distinct


 var qry =(from c in ctx.STGP_GetProductInteractionsBySearchText(ProductId,searchText)
select new ProductInteractionSummary()
{
InteractionSeverityId =(int)i.iInteractionSeverityID,
ExistingDrugInteractionText = i.sOtherDrugInteractionText,
FormattedInteractionMessage = i.FormattedInteractionMessage,
InteractionSeverityText = i.sInteractionSeverityText
})。Distinct();分配到列表时



 list =(List< ProductInteractionSummary>)qry.ToList< ProductInteractionSummary>()。Distinct(); 


它们都返回相同的20条记录 - 因此当分配给网格时,我得到20行;当我只需要2


那么你如何使用Distinct,而不是针对一列 - 而是整个行中的一个列。


I不能在SQL端执行,因为那时我要么得到相同的20行,要么它们现在是不同的值,这将组成一个唯一的密钥。


 


我不确定我是否可以在主键中使用文本字段 - 但这需要我通过修改Entity建模器后面的XML来手动设置密钥。我还需要更改存储过程以返回我想要的字段。


 


 


在qry之后将其分配给列表


将其分配给列表后

解决方案

有几个实现目标的方法:


 


1)使用与自定义相等比较器的区别


Distinct isn’ t doing your want,因为它正在使用Object .Equals t o比较ProductInteractionSummary的每个实例


有一个Distinct的重载接受一个I​​EqualityComparer< T>这可以非常简单地实现你的目标


 


2)在模型中创建ProductInteractionSummary作为复杂类型,并使存储过程具体化


(类型只需要一个主键,如果它们是一个完整的实体类型(允许创建/更新/删除))


步骤将是:


-  更新存储过程以进行区分,只需选择您想要的列


-  将复杂类型(如现有的ProductInteractionSummary)添加到模型


   (在设计师的表面;‘右键点击 - >添加 - >复杂类型’)


- 为存储过程创建函数导入并将返回类型设置为复杂类型


  
(在设计师的表面上;‘右键点击 - > ;添加 - >功能导入…’)


- 创建函数导入后,您将在派生的上下文类型上有一个方法来调用函数


 


选项2的优点是Distinct在数据库中而不是在内存中处理


I have already posted a question as to why the Entity modeller insists on a unique key here; http://social.msdn.microsoft.com/Forums/en-GB/adodotnetentityframework/thread/bde61fbf-2038-4ed3-a1f6-c5cfa2d3ae42

However I am having difficulty with one query which prompted that question.

 

Basically I have the following SQL Server Stored Procedure

 

ALTER PROCEDURE [dbo].[STGP_GetProductInteractionsBySearchText] 
	-- Add the parameters for the stored procedure here
	@ProductID int, 
	@SearchText varchar(100) = ''
AS
BEGIN
	SELECT iProductID
			, iInteractionSeverityID
			, sInteractionSeverityText
			, FormattedInteractionMessage
			, sOtherDrugInteractionText
			, iClinicalSetID
			, iInteractionGroupID1
			, iInteractionGroupID2
			, iInteractionMessageID
			, iInteractionMessageStyleID
			, sInteractionText
			, sInteractionMessageStyleText
			, sInteractionMessageText
			, iOtherDrugProductID
			, sOtherDrugDisplayName
			, iOtherDrugClinicalSetID
	FROM  STGV_ProductInteractions
	WHERE  (iProductID = @ProductID) 
			AND (sOtherDrugDisplayName LIKE '%' + @SearchText + '%')

END

 

Now if I pass it the product ID 1015729 and the word 'paracetamol' then I get 20 results back;

1015729 3 Usually avoid combination. Use combination only under special circumstances, taking any necessary action to reduce risk.   INCREASED RISK OF BLEEDING ASPIRIN/SODIUM SALICYLATE 2315 141 26 19 3 NSAIDS

This is because there are 20 products giving the same interaction.

 

However my users do not need to see all of this. They only want to see

3 Usually avoid combination. Use combination only under special circumstances, taking any necessary action to reduce risk. INCREASED RISK OF BLEEDING ASPIRIN/SODIUM SALICYLATE

This removes the productId which provides a unique key for the entity modeller.

So my web service which returns the set the user wants is as follows;

    public List<ProductInteractionSummary> GetProductInteractionsSummary(int ProductId, String searchText)
    {
      List<ProductInteractionSummary> list = null;
      STGMDDFFormularyEntities ctx = null;

      try
      {
        ctx = new STGMDDFFormularyEntities();

        var qry = from i in ctx.STGP_GetProductInteractionsBySearchText(ProductId, searchText)
             select new ProductInteractionSummary()
             {
               InteractionSeverityId = (int)i.iInteractionSeverityID,
               ExistingDrugInteractionText = i.sOtherDrugInteractionText,
               FormattedInteractionMessage = i.FormattedInteractionMessage,
               InteractionSeverityText = i.sInteractionSeverityText
             };

        list = qry.ToList<ProductInteractionSummary>();

        
      }
      catch (System.Exception ex)
      {
        throw ex;
      }

      
      return list;
    }

this returns a list with just the properties I require. However it still has 20 records.

 

I have tried various forms of Distinct

 

Such as surrounding the linq query in brackets and putting Distinct afterwards

var qry = (from i in ctx.STGP_GetProductInteractionsBySearchText(ProductId, searchText)
             select new ProductInteractionSummary()
             {
               InteractionSeverityId = (int)i.iInteractionSeverityID,
               ExistingDrugInteractionText = i.sOtherDrugInteractionText,
               FormattedInteractionMessage = i.FormattedInteractionMessage,
               InteractionSeverityText = i.sInteractionSeverityText
             }).Distinct();

when assigning to the list

list = (List<ProductInteractionSummary>)qry.ToList<ProductInteractionSummary>().Distinct();

They all return the same 20 records - so when assigned to a grid I get 20 rows; when I only need 2

So how can you use Distinct, not against one column - but one which is distinct across the whole row.

I can't do it at the SQL end because then I either get the same 20 rows or their is now distinct value which will make up a unique key.

 

I'm not sure if I can use text fields in the primary key - but this would require me to manually set the key by modifying the XML which is behind the Entity modeller. I would also need to alter the Stored Procedure to return back just the fields I want.

 

 

Placing the distinct after the qry when assigning it to the list

After assigning it to the list

解决方案

There are a couple of ways to achieve what you are after:

 

1) Use Distinct with a custom equality comparer

Distinct isn’t doing what you want because it is using Object.Equals to compare each instance of ProductInteractionSummary

There is an overload of Distinct that accepts an IEqualityComparer<T> which would be very simple to implement for what you are after

 

2) Create ProductInteractionSummary as a complex type in your model and have the stored procedure materialize to it

(Types only need to have a primary key if they are a full entity type (to allow create/update/delete))

Steps would be:

- Update the stored procedure to do the Distinct and just select the columns you want

- Add a complex type (like your existing ProductInteractionSummary) to the model
   (On the designer surface; ‘Right Click -> Add -> Complex Type’)

- Create a function import for the stored procedure and set the return type to be the complex type

   (On the designer surface; ‘Right Click -> Add -> Function Import…’)

- After creating the Function Import you will have a method on your derived context type to call the function

 

The advantage of option 2 is that the Distinct is processed in the database rather than in memory


这篇关于从LINQ查询获取不同的行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆