Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 由运行时已知的属性创建的Linq2SQL组_C#_Linq To Sql_Grouping_Linq To Objects_Linq Expressions - Fatal编程技术网

C# 由运行时已知的属性创建的Linq2SQL组

C# 由运行时已知的属性创建的Linq2SQL组,c#,linq-to-sql,grouping,linq-to-objects,linq-expressions,C#,Linq To Sql,Grouping,Linq To Objects,Linq Expressions,我试图根据用户输入频率(每日、每月、每年)返回一些报告数据。我的LINQ如下所示: var dataQuery = DataAccess.AppEventRepository.AllNoTracking; // get property func based on provided filter Func<AppEvent, DateTime?> timeGroupProp = null; if (filters.TimeSpanId == (int)TimeSpanEnum.Da

我试图根据用户输入频率(每日、每月、每年)返回一些报告数据。我的LINQ如下所示:

var dataQuery = DataAccess.AppEventRepository.AllNoTracking;

// get property func based on provided filter
Func<AppEvent, DateTime?> timeGroupProp = null;
if (filters.TimeSpanId == (int)TimeSpanEnum.Daily) timeGroupProp = e => e.InsertDay;
if (filters.TimeSpanId == (int) TimeSpanEnum.Monthly) timeGroupProp = e => e.InsertMonth;
if (filters.TimeSpanId == (int) TimeSpanEnum.Yearly) timeGroupProp = e => e.InsertYear;

 var groupedDataQuery = dataQuery
    // downgrading to LINQ2Object, because Invoke is not supported in LINQ2SQL
    .ToList()
    .GroupBy(e => new {InsertGroupProp = timeGroupProp?.Invoke(e), e.CountryId})
    .Select(grp => new AuditReportGroupingDataModel
    {
        GroupTime = grp.Key.InsertGroupProp.Value,
        CountryId = grp.Key.CountryId.Value,
        Count = grp.Count()
     });
var-dataQuery=DataAccess.appendrepository.AllNoTracking;
//根据提供的筛选器获取属性func
Func timeGroupProp=null;
如果(filters.TimeSpanId==(int)TimeSpanEnum.Daily)timeGroupProp=e=>e.InsertDay;
如果(filters.TimeSpanId==(int)TimeSpanEnum.Monthly)timeGroupProp=e=>e.InsertMonth;
如果(filters.TimeSpanId==(int)TimeSpanEnum.year)timeGroupProp=e=>e.InsertYear;
var groupedDataQuery=dataQuery
//降级到LINQ2Object,因为LINQ2SQL中不支持调用
托利斯先生()
.GroupBy(e=>new{InsertGroupProp=timeGroupProp?.Invoke(e),e.CountryId})
.选择(grp=>new AuditReportGroupingDataModel
{
GroupTime=grp.Key.InsertGroupProp.Value,
CountryId=grp.Key.CountryId.Value,
Count=grp.Count()
});
这是正确的,但问题是分组是在从SQL检索所有数据之后完成的。未来事件的数量可能会增加到数十万,我预计性能会下降


问题:是否可以编写查询以便在服务器端级别进行分组?(充分使用LINQ2SQL,而不是降级到LINQ2Object)

我设法找到了两种方法来实现这一点,但不是像
Invoke
试用这样的小方法

0)我正在使用一些POCO来存储数据

public class AuditReportGroupingDataModelBase
{
    public DateTime GroupTime { get; set; }
    public int CountryId { get; set; }
}

public class AuditReportGroupingDataModel : AuditReportGroupingDataModelBase
{
    public int Count { get; set; }
}
1)丑陋的方式-在GroupBy中使用条件运算符

我的少量可能性允许使用三元运算符。但是,对于数量增加的选项来说,这并不能正常工作

var groupedDataQuery = dataQuery
    .GroupBy(e => new AuditReportGroupingDataModelBase
    {
        GroupTime = (filters.TimeSpanId == (int)TimeSpanEnum.Daily ? e.InsertDay : filters.TimeSpanId == (int)TimeSpanEnum.Monthly ? e.InsertMonth : e.InsertDay).Value,
        CountryId = e.CountryId.Value
    })
    .Select(grp => new AuditReportGroupingDataModel
    {
        GroupTime = grp.Key.GroupTime,
        CountryId = grp.Key.CountryId,
        Count = grp.Count()
    });
这是可行的,但会生成一条丑陋且效率不高的SQL语句:

exec sp_executesql N'SELECT 
    1 AS [C1], 
    [GroupBy1].[K2] AS [C2], 
    [GroupBy1].[K1] AS [CountryId], 
    [GroupBy1].[A1] AS [C3]
    FROM ( SELECT 
        [Filter1].[K1] AS [K1], 
        [Filter1].[K2] AS [K2], 
        COUNT([Filter1].[A1]) AS [A1]
        FROM ( SELECT 
            [Extent1].[CountryId] AS [K1], 
            CASE WHEN (1 = @p__linq__0) THEN [Extent1].[InsertDay] WHEN (2 = @p__linq__1) THEN [Extent1].[InsertMonth] ELSE [Extent1].[InsertDay] END AS [K2], 
            1 AS [A1]
            FROM [dbo].[AppEvent] AS [Extent1]
            WHERE ([Extent1].[EventTypeId] IN (1)) AND ([Extent1].[CountryId] IS NOT NULL)
        )  AS [Filter1]
        GROUP BY [K1], [K2]
    )  AS [GroupBy1]',N'@p__linq__0 int,@p__linq__1 int',@p__linq__0=1,@p__linq__1=1
2)更好的方式-基于值的分组表达式

        IQueryable<IGrouping<AuditReportGroupingDataModelBase, AppEvent>> groupedDataQueryInterm = null;
        if (filters.TimeSpanId == (int)TimeSpanEnum.Daily) groupedDataQueryInterm = dataQuery.GroupBy(e => new AuditReportGroupingDataModelBase { GroupTime = e.InsertDay.Value, CountryId = e.CountryId.Value });
        if (filters.TimeSpanId == (int)TimeSpanEnum.Monthly) groupedDataQueryInterm = dataQuery.GroupBy(e => new AuditReportGroupingDataModelBase { GroupTime = e.InsertMonth.Value, CountryId = e.CountryId.Value });
        if (filters.TimeSpanId == (int)TimeSpanEnum.Yearly) groupedDataQueryInterm = dataQuery.GroupBy(e => new AuditReportGroupingDataModelBase { GroupTime = e.InsertYear.Value, CountryId = e.CountryId.Value });
        if (groupedDataQueryInterm == null)
            throw new InvalidEnumArgumentException($@"Invalid value provided to {nameof(filters.TimeSpanId)}");

        var groupedDataQuery = groupedDataQueryInterm
            .Select(grp => new AuditReportGroupingDataModel
            {
                GroupTime = grp.Key.GroupTime,
                CountryId = grp.Key.CountryId,
                Count = grp.Count()
            })

现在可以肯定的是,LINQ2SQL将linq查询转换为SQL,我认为您不能使用invoke方法。您可以在启动查询之前放置调用,并在LINQ2SQL中使用结果
SELECT 
    1 AS [C1], 
    [GroupBy1].[K2] AS [InsertDay], 
    [GroupBy1].[K1] AS [CountryId], 
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT 
        [Extent1].[CountryId] AS [K1], 
        [Extent1].[InsertDay] AS [K2], 
        COUNT(1) AS [A1]
        FROM [dbo].[AppEvent] AS [Extent1]
        WHERE ([Extent1].[EventTypeId] IN (1)) AND ([Extent1].[CountryId] IS NOT NULL)
        GROUP BY [Extent1].[CountryId], [Extent1].[InsertDay]
    )  AS [GroupBy1]