C# 操作与linq相交
对不起,这个问题的标题很奇怪,但我不知道如何把它表达得更简短。如果你知道如何更好地表达它,我将很高兴你编辑我的问题。 因此,我有下表: 我正在查询C# 操作与linq相交,c#,linq,entity-framework-core,C#,Linq,Entity Framework Core,对不起,这个问题的标题很奇怪,但我不知道如何把它表达得更简短。如果你知道如何更好地表达它,我将很高兴你编辑我的问题。 因此,我有下表: 我正在查询CustomerId和EventType字段。剩下的并不重要。我想您应该理解这个表类似于按客户记录事件。一些客户制造事件-我的表中有事件。简单 我需要选择所有客户事件,其中每个客户都有类型为注册和类型为存款的事件。换句话说,客户以前是否有过注册?同一客户有存款?如果是和是-我需要选择此客户的所有事件 我如何在LINQ的帮助下做到这一点 所以我可以像这
CustomerId
和EventType
字段。剩下的并不重要。我想您应该理解这个表类似于按客户记录事件。一些客户制造事件-我的表中有事件。简单
我需要选择所有客户事件,其中每个客户都有类型为注册
和类型为存款
的事件。换句话说,客户以前是否有过注册
?同一客户有存款
?如果是和是-我需要选择此客户的所有事件
我如何在LINQ
的帮助下做到这一点
所以我可以像这样编写SQL
select *
From "CustomerEvents"
where "CustomerId" in (
select distinct "CustomerId"
from "CustomerEvents"
where "EventType" = 'deposit'
intersect
select distinct "CustomerId"
from "CustomerEvents"
where "EventType" = 'registration'
)
它可以工作,但是如何在LINQ上编写它呢
第二个问题。上面的SQL是可行的,但它不是通用的。如果明天我需要展示客户的活动,这些客户有注册
,存款
和-new one event-访问
?我必须写一个新的查询。比如:
select *
From "CustomerEvents"
where "CustomerId" in (
select "CustomerId"
from "CustomerEvents"
where "EventType" = 'deposit'
intersect
select distinct "CustomerId"
from "CustomerEvents"
where "EventType" = 'registration'
intersect
select distinct "CustomerId"
from "CustomerEvents"
where "EventType" = 'visit'
)
不舒服:(
作为源数据,我有一个带有事件类型的列表。有什么方法可以动态地创建它吗?我的意思是,列表中有一个新的事件-我有一个新的事件
我使用Postgres和.NETCore3.1
更新
我渴望有一个计划
我还没有测试过这是否能正确转换为SQL,但是如果我们假设
ctx.CustomerEvents
是DbSet
,您可以尝试以下方法:
var targetCustomerId=ctx
.客户事件
.GroupBy(事件=>event.CustomerId)
。其中(分组=>
已分组。任何(事件=>event.EventType==“存款”)
&&任何(event=>event.EventType==“注册”))
.选择(x=>x.Key)
.ToList();
然后为这些客户选择所有事件:
var events=ctx.CustomerEvents.Where(event=>targetCustomerIds.Contains(event.CustomerId));
要使用不同数量的事件类型动态获取targetCustomerID
,您可以尝试以下方法:
//例如
var requiredEventTypes=new[]{“存款”、“注册”};
//按客户ID划分的第一组
var groupedByCustomerId=ctx
.客户事件
.GroupBy(event=>event.CustomerId);
//然后过滤掉任何不满足条件的分组
var filtered=GetFilteredGroups(groupedByCustomerId,requiredEventTypes);
//然后选择目标客户ID
var targetCustomerIds=filtered.Select(x=>x.Key).ToList();
//最后,选择您的目标事件
var events=ctx.CustomerEvents.Where(事件=>
targetCustomerId.Contains(event.CustomerId));
您可以这样定义GetFilteredGroups
方法:
私有静态IQueryable GetFilteredGroup(
易读的分组,
IEnumerable requiredEventTypes)
{
var result=grouping.Where(x=>true);
foreach(requiredEventTypes中的var事件类型)
{
result=result.Where(x=>x.Any(event=>event.EventType==EventType));
}
返回结果;
}
或者,您可以尝试直接从筛选的分组中选择目标事件,而不是选择目标客户ID:
/。。。
//筛选出任何不满足条件的分组
var filtered=GetFilteredGroups(groupedByCustomerId,requiredEventTypes);
//在此处选择您的活动
var results=filtered.SelectMany(x=>x.Distinct().ToList();
关于无法将查询转换为SQL的问题
根据您的数据库大小,尤其是CustomerEvents
表的大小,此解决方案可能是理想的,也可能不是理想的,但您可以将优化的集合加载到内存中并在其中执行分组:
//例如
var requiredEventTypes=new[]{“存款”、“注册”};
//按客户ID第一组,但加载到内存中
var groupedByCustomerId=ctx
.客户事件
.Where(event=>requiredEventTypes.Contains(event.EventType))
.选择(事件=>new CustomerEventViewModel
{
Id=event.Id,
CustomerId=event.CustomerId,
EventType=event.EventType
})
.GroupBy(事件=>event.CustomerId)
.AsEnumerable();
//然后过滤掉任何不满足条件的分组
var filtered=GetFilteredGroups(groupedByCustomerId,requiredEventTypes);
//然后选择目标客户ID
var targetCustomerIds=filtered.Select(x=>x.Key).ToList();
//最后,选择您的目标事件
var events=ctx.CustomerEvents.Where(事件=>
targetCustomerId.Contains(event.CustomerId));
您需要像这样创建一个名为CustomerEventViewModel
的类型(这样您就不必将整个CustomerEvent
实体实例加载到内存中):
公共类CustomerEventViewModel
{
公共int Id{get;set;}
public int CustomerId{get;set;}
公共字符串事件类型{get;set;}
}
并将GetFilteredGroups
更改如下:
私有静态IEnumerable GetFilteredGroup(
IEnumerable分组,
IEnumerable requiredEventTypes)
{
var result=grouping.Where(x=>true);
foreach(requiredEventTypes中的var事件类型)
{
result=result.Where(x=>x.Any(event=>event.EventType==EventType));
}
返回结果;
}
它现在应该可以正常工作了。谢谢@Dejan Janjušević。他是一个没有激情的开发人员。但EF似乎无法将他的解决方案转换为SQL(或者只是我的手从错误的地方长出来)。我在这里发布了针对这种情况的解决方案。它很简单。因此。我在表
EventType
中有。它是字符串。我从客户端收到了以下筛选请求:
List<string> eventType
列表事件类型
仅列出事件类型
if (eventType.Any())
{
List<int> ids = new List<int>();
foreach (var e in eventType)
{
var customerIdsList =
_context.customerEvents.Where(x => x.EventType == e).Select(x => x.CustomerId.Value).Distinct().ToList();
if (!ids.Any())
{
ids = customerIdsList;
}
else
{
ids = ids.Intersect(customerIdsList).ToList();
}
}
customerEvents = customerEvents.Where(x => ids.Contains(x.CustomerId.Value));
}