Linq .GroupBy .Where .Select 新建分组项
Linq .GroupBy .Where .Select new Grouping item
我正在尝试构建一个更改日志查询,以提取自上次修订以来的日志。
我现在需要根据一些规则合并日志。
这是我的更新日志模型:
public abstract class ChangeLogObject : TrackedObject {
/// <summary>
/// Type of transaction that occured
/// </summary>
public ChangeType ChangeType { get; set; }
/// <summary>
/// Original Id of the stateful object this changelog was created against
/// </summary>
public long EntityId { get; set; }
}
public enum ChangeType {
Created,
Updated,
Deleted
}
所以我需要遵循的步骤是:
获取 Id > 上次修订
按 EntityId 分组
不要带回实体有 ChangeType.Created 和 ChangeType.Deleted
的任何组
如果有 ChangeType.Deleted 但没有 ChangeType.Created,则不要带回 ChangeType.Updated 记录(从组中删除更新的记录)
如果有多个
只带回最后ChangeType.Updated条记录
如果该组包含 ChangeType.Created 和 ChangeType.Updated 则只带回最后一个 ChangeType.Updated 但将其更改为 ChangeType.Created
这是我已经达到的程度,但我不知道如何'bring back part of a group':
var newChanges =
// 1. Get where greater than last revision
srcSet.Where(x => x.Id > lastRevision)
// 2. Group by EntityId
.GroupBy(x => x.EntityId)
// 3. Don't bring back created and deleted (it's come and gone)
.Where(x => !(x.Any(y => y.ChangeType == ChangeType.Created) &&
x.Any(y => y.ChangeType == ChangeType.Deleted)))
// 4. Only bring back Deleted if no created (don't edit something you're about to delete)
.Where(x => (!x.Any(y => y.ChangeType == ChangeType.Created) &&
x.Any(y => y.ChangeType == ChangeType.Deleted)))
//create new grouping, but only use the delete record????
//convert back to individual change logs
.Select(x => x.ToList()
//maybe order by ID?
.OrderBy(y => y.Id));
对于 4. 如果组本身不包含 ChangeType.Created 但可能包含 [,我如何将 x 变成一个只有 records/values 的新组 ChangeType.Deleted =55=]?
我做出的一些假设:
srcSet
是一组 ChangeLogObject
项。
- 根据列表中的要求 5,要启用 "last" 项目的检索,您应该能够按某个值对列表进行排序。为此,我引入了一个
ChangeDate
字段,它是更改发生的日期。
在我的示例中,TrackedObject
如下所示:
public abstract class TrackedObject
{
public int Id { get; set; }
public DateTime ChangeDate { get; set; }
}
我把查询的每一步都分解了,并按要求编号:
var lastRevision = 2;
var srcSet = new List<ChangeLogObject>();
// 1. & 2.
var entityGroupsByEntityId = srcSet
.Where(m => m.Id > lastRevision) // greater than last revision
//.OrderByDescending(m => m.ChangeDate)
.GroupBy(m => m.EntityId)
.Select(group => new
{
EntityId = group.Key,
ChangeCount = group.Count(),
Changes = group.ToList().OrderByDescending(m => m.ChangeDate)
});
// 3.
var entityGroupsWithNoDeleteAndCreate = entityGroupsByEntityId
.Where(group => !(group.Changes.Any(m => m.ChangeType == ChangeType.Created)
&& group.Changes.Any(m => m.ChangeType == ChangeType.Deleted))); // it doesn't contain both creates and deletes
// 4.
var entityGroupsWithoutDeletedAndNoCreate = entityGroupsWithNoDeleteAndCreate
.Where(group => !(group.Changes.Any(m => m.ChangeType == ChangeType.Deleted)
&& (group.Changes.Count(m => m.ChangeType == ChangeType.Created) < 1))); // it doesn't contain a delete without a create
// 5.
var entityGroupsWithUpdatedButNoCreated = entityGroupsWithoutDeletedAndNoCreate
.Where(group => group.Changes.Any(m => m.ChangeType == ChangeType.Updated)
&& !group.Changes.Any(m => m.ChangeType == ChangeType.Created)) // it updated but not created
.Select(group => new ChangeLogObject
{
EntityId = group.EntityId,
ChangeDate = group.Changes.First().ChangeDate,
ChangeType = group.Changes.First().ChangeType // don't change the type
});
// 6.
var entityGroupsWithCreatedAndUpdatedOnly = entityGroupsWithoutDeletedAndNoCreate
.Where(group => group.Changes.Any(m => m.ChangeType == ChangeType.Created)
&& group.Changes.Any(m => m.ChangeType == ChangeType.Updated)) // it contains both created and updated
.Select(group => new ChangeLogObject
{
EntityId = group.EntityId,
ChangeDate = group.Changes.First(m => m.ChangeType == ChangeType.Updated).ChangeDate, // bring back the first updated record
ChangeType = ChangeType.Created // change the type to created
});
// Join the 2 sets of Updated and Created changes
var finalResult = entityGroupsWithUpdatedButNoCreated.Union(entityGroupsWithCreatedAndUpdatedOnly).ToList();
警告:
- linq 语句未针对性能进行优化,因为它们未包含在 IQueryable 中以确保这些查询是在数据库而不是内存中计算的。
这应该足以让您开始将需求的每个部分分解为一个查询。
我正在尝试构建一个更改日志查询,以提取自上次修订以来的日志。
我现在需要根据一些规则合并日志。
这是我的更新日志模型:
public abstract class ChangeLogObject : TrackedObject {
/// <summary>
/// Type of transaction that occured
/// </summary>
public ChangeType ChangeType { get; set; }
/// <summary>
/// Original Id of the stateful object this changelog was created against
/// </summary>
public long EntityId { get; set; }
}
public enum ChangeType {
Created,
Updated,
Deleted
}
所以我需要遵循的步骤是:
获取 Id > 上次修订
按 EntityId 分组
不要带回实体有 ChangeType.Created 和 ChangeType.Deleted
的任何组
如果有 ChangeType.Deleted 但没有 ChangeType.Created,则不要带回 ChangeType.Updated 记录(从组中删除更新的记录)
如果有多个
只带回最后ChangeType.Updated条记录
如果该组包含 ChangeType.Created 和 ChangeType.Updated 则只带回最后一个 ChangeType.Updated 但将其更改为 ChangeType.Created
这是我已经达到的程度,但我不知道如何'bring back part of a group':
var newChanges =
// 1. Get where greater than last revision
srcSet.Where(x => x.Id > lastRevision)
// 2. Group by EntityId
.GroupBy(x => x.EntityId)
// 3. Don't bring back created and deleted (it's come and gone)
.Where(x => !(x.Any(y => y.ChangeType == ChangeType.Created) &&
x.Any(y => y.ChangeType == ChangeType.Deleted)))
// 4. Only bring back Deleted if no created (don't edit something you're about to delete)
.Where(x => (!x.Any(y => y.ChangeType == ChangeType.Created) &&
x.Any(y => y.ChangeType == ChangeType.Deleted)))
//create new grouping, but only use the delete record????
//convert back to individual change logs
.Select(x => x.ToList()
//maybe order by ID?
.OrderBy(y => y.Id));
对于 4. 如果组本身不包含 ChangeType.Created 但可能包含 [,我如何将 x 变成一个只有 records/values 的新组 ChangeType.Deleted =55=]?
我做出的一些假设:
srcSet
是一组ChangeLogObject
项。- 根据列表中的要求 5,要启用 "last" 项目的检索,您应该能够按某个值对列表进行排序。为此,我引入了一个
ChangeDate
字段,它是更改发生的日期。
在我的示例中,TrackedObject
如下所示:
public abstract class TrackedObject
{
public int Id { get; set; }
public DateTime ChangeDate { get; set; }
}
我把查询的每一步都分解了,并按要求编号:
var lastRevision = 2;
var srcSet = new List<ChangeLogObject>();
// 1. & 2.
var entityGroupsByEntityId = srcSet
.Where(m => m.Id > lastRevision) // greater than last revision
//.OrderByDescending(m => m.ChangeDate)
.GroupBy(m => m.EntityId)
.Select(group => new
{
EntityId = group.Key,
ChangeCount = group.Count(),
Changes = group.ToList().OrderByDescending(m => m.ChangeDate)
});
// 3.
var entityGroupsWithNoDeleteAndCreate = entityGroupsByEntityId
.Where(group => !(group.Changes.Any(m => m.ChangeType == ChangeType.Created)
&& group.Changes.Any(m => m.ChangeType == ChangeType.Deleted))); // it doesn't contain both creates and deletes
// 4.
var entityGroupsWithoutDeletedAndNoCreate = entityGroupsWithNoDeleteAndCreate
.Where(group => !(group.Changes.Any(m => m.ChangeType == ChangeType.Deleted)
&& (group.Changes.Count(m => m.ChangeType == ChangeType.Created) < 1))); // it doesn't contain a delete without a create
// 5.
var entityGroupsWithUpdatedButNoCreated = entityGroupsWithoutDeletedAndNoCreate
.Where(group => group.Changes.Any(m => m.ChangeType == ChangeType.Updated)
&& !group.Changes.Any(m => m.ChangeType == ChangeType.Created)) // it updated but not created
.Select(group => new ChangeLogObject
{
EntityId = group.EntityId,
ChangeDate = group.Changes.First().ChangeDate,
ChangeType = group.Changes.First().ChangeType // don't change the type
});
// 6.
var entityGroupsWithCreatedAndUpdatedOnly = entityGroupsWithoutDeletedAndNoCreate
.Where(group => group.Changes.Any(m => m.ChangeType == ChangeType.Created)
&& group.Changes.Any(m => m.ChangeType == ChangeType.Updated)) // it contains both created and updated
.Select(group => new ChangeLogObject
{
EntityId = group.EntityId,
ChangeDate = group.Changes.First(m => m.ChangeType == ChangeType.Updated).ChangeDate, // bring back the first updated record
ChangeType = ChangeType.Created // change the type to created
});
// Join the 2 sets of Updated and Created changes
var finalResult = entityGroupsWithUpdatedButNoCreated.Union(entityGroupsWithCreatedAndUpdatedOnly).ToList();
警告:
- linq 语句未针对性能进行优化,因为它们未包含在 IQueryable 中以确保这些查询是在数据库而不是内存中计算的。
这应该足以让您开始将需求的每个部分分解为一个查询。