-
-
Notifications
You must be signed in to change notification settings - Fork 35
/
EntityBucketCollection.cs
96 lines (78 loc) · 2.68 KB
/
EntityBucketCollection.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
using System;
using System.Collections.Generic;
using System.Linq;
namespace MongoFramework.Infrastructure
{
public class EntityBucketCollection<TGroup, TSubEntity> where TGroup : class
{
private Dictionary<TGroup, List<TSubEntity>> SubEntityStaging { get; }
private IEntityReader<EntityBucket<TGroup, TSubEntity>> EntityReader { get; }
public int BucketSize { get; }
public EntityBucketCollection(IEntityReader<EntityBucket<TGroup, TSubEntity>> entityReader, int bucketSize)
{
SubEntityStaging = new Dictionary<TGroup, List<TSubEntity>>(new ShallowPropertyEqualityComparer<TGroup>());
EntityReader = entityReader;
BucketSize = bucketSize;
}
public void AddEntity(TGroup group, TSubEntity entity)
{
if (!SubEntityStaging.ContainsKey(group))
{
SubEntityStaging.Add(group, new List<TSubEntity> { entity });
}
else
{
SubEntityStaging[group].Add(entity);
}
}
public IEntityCollection<EntityBucket<TGroup, TSubEntity>> AsEntityCollection()
{
var entityCollection = new EntityCollection<EntityBucket<TGroup, TSubEntity>>();
foreach (var grouping in SubEntityStaging)
{
var entityList = grouping.Value;
var sliceAt = 0;
var currentBucketIndex = 1;
var remainingEntitiesCount = entityList.Count;
//Identify last bucket of the group for the last index and to potentially backfill into it (if there is space)
var bucket = EntityReader.AsQueryable().Where(e => e.Group == grouping.Key).OrderByDescending(e => e.Index).FirstOrDefault();
if (bucket != null)
{
//Check if there is room to backfill into the existing bucket
if (bucket.ItemCount < bucket.BucketSize)
{
var sliceSize = Math.Min(bucket.BucketSize - bucket.ItemCount, remainingEntitiesCount);
var sliceEntities = entityList.Take(sliceSize).ToArray();
bucket.Items.AddRange(sliceEntities);
bucket.ItemCount += sliceSize;
entityCollection.Update(bucket, EntityEntryState.Updated);
sliceAt += sliceSize;
remainingEntitiesCount -= sliceSize;
}
currentBucketIndex = bucket.Index + 1;
}
while (remainingEntitiesCount > 0)
{
var sliceSize = Math.Min(BucketSize, remainingEntitiesCount);
var sliceEntities = entityList.Skip(sliceAt).Take(sliceSize).ToList();
entityCollection.Add(new EntityBucket<TGroup, TSubEntity>
{
Group = grouping.Key,
Index = currentBucketIndex,
ItemCount = sliceSize,
BucketSize = BucketSize,
Items = sliceEntities
});
currentBucketIndex++;
sliceAt += sliceSize;
remainingEntitiesCount -= sliceSize;
}
}
return entityCollection;
}
public void Clear()
{
SubEntityStaging.Clear();
}
}
}