Description
I would like to propose to change IEntityDiff<T>
to IDiffableEntityHashSet<T>
which introduces a change in behaviour that I believe is more intuitive. We can still come up with a better name, but the meat of this proposal is the change of behaviour, as discussed below.
Why?
Because I think the current behaviour of IEntityDiff<T>
is not very intuitive. Let's explore this by comparing the BeforeUpdate
hook, where the diff is used, with the BeforeCreate
hook, where the more intuitive IEntityHashSet<T>
is used. We want them to behave more or less the same, but IEntityDiff<T>
deviates from IEntityHashSet<T>
in a non-intuitive way.
The solution is then to replace IEntityDiff<T>
with IDiffableEntityHashSet<T>
so that the behaviour is similar again.
BeforeCreate
In the BeforeCreate
hook we have a IEntityHashSet<T>
, which is basically just a hashset with some extra helpermethods that relate to affected relationships.
// intuitive: the IEntityHashSet parameter is just a HashSet of entities which the hook is fired
public override IEnumerable<Tag> BeforeCreate(IEntityHashSet<Tag> entities, ResourcePipeline pipeline)
{
// which means we can loop over entities:
foreach (Tag tag in entities)
{
// do something with tag
}
// But IEntityHashSet not just a HashSet: its a hashset PLUS some
// helpermethods to access information about affected relationships to other models.
var tagsAssignedToArticles = entities.GetByRelationship<Article>();
var tagsAssignedToBlogs = entities.GetByRelationship<Blog>();
// lastly, we can return a filtered list of the affected tags by just using
// LINQ on our IEntityHashSet, because IEntityHashSet is basically just a HashSet.
return entities.Where( e => SomeCondition(e));
}
From the comments in the above example it should be clear why IEntityHashSet<T>
is more or less just a HashSet<T>
.
BeforeUpdate currently
Let's now compare IEntityDiff<T>
as used in BeforeUpdate with IEntityHashSet<T>
. It does not behave the same:
// I think it would be intuitive if, like with BeforeCreate, let the IEntityDiffs<Tag>
// just be a hashset of affected entities PLUS relationship helpermethods and now also
// PLUS some helper methods related to diffs. But it is not. The example below shows
// how it is different from this behaviour
public override IEnumerable<Tag> BeforeUpdate(IEntityDiffs<Tag> entityDiff, ResourcePipeline pipeline)
{
// we loop over DiffPairs, not the affected tags.
// so IEntityDiffs behaves like a collection of EntityDiffPairs<T>, not a collection of T
foreach (EntityDiffPair<Tag> element in entityDiff)
{
var entityFromRequestBody = element.Entity;
var entityFromDatabase = element.DatabaseValue;
}
// the return type of the hook, however, is still IEnumerable<T>.
// so we need to get that collection by accessing it manually like below, and return that
return entityDiff.Entities;
}
From the above examples it should be clear that IEntityHashSet<T>
behaves like a collection of T, whereas IEntityDiff<T>
does not. The current proposal is to change IEntityDiff<T>
to IEntityHashSetDiff<T>
so that it does.
BeforeUpdate proposed
The before update hook will then look like this:
// Now IDiffableEntityHashSet <Tag> behaves just like a collection of tags again
public override IEnumerable<Tag> BeforeUpdate(IDiffableEntityHashSet<Tag> entities, ResourcePipeline pipeline)
{
// Now we're looping over tags again: the affected entities from the request
foreach (Tag element in entities)
{
// do something with tag
}
// we can still loop over the DiffPairs to check out the current database value
// of each affected entity in the request
foreach (EntityDiffPair<Tag> element in entities.GetDiffs())
{
var entityFromRequestBody = element.Entity;
var entityFromDatabase = element.DatabaseValue;
}
// we can just return the list of affected entities again (or a filtered version of that)
return entities.Where(e => SomeCondition(e));
}
In conclusion
Where IEntityHashSet<T>
is just a HashSet<T>
with some helper methods for accessing relationships, IDiffableEntityHashSet<T>
will be just a IEntityHashSet<T>
with yet another helper method:GetDiffs()
, which gives the ability to loop over diffed values of affected entities.