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));
}