Created
May 30, 2017 16:36
-
-
Save vkhorikov/99c43fada0575b0751825a560a884732 to your computer and use it in GitHub Desktop.
Source code for the 2nd code review
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Fabric : AggregateRootWithLinkedObjects | |
{ | |
public bool PreOrder { get; protected set; } | |
private string _Due { get; set; } | |
public Maybe<string> Due | |
{ | |
get => _Due; | |
protected set => _Due = value.Unwrap(); | |
} | |
protected virtual ICollection<FabricImage> _Images { get; set; } | |
public IEnumerable<FabricImage> Images => _Images.Skip(0); | |
protected virtual ICollection<FabricTag> _Tags { get; set; } | |
public IEnumerable<FabricTag> Tags => _Tags.Skip(0); | |
protected Fabric() | |
{ | |
_Images = new Collection<FabricImage>(); | |
_Tags = new Collection<FabricTag>(); | |
} | |
internal static Fabric Create(int[] imageIds, int[] tagIds, bool preOrder, Maybe<string> due) | |
{ | |
Guard.ForDuplicates(imageIds, "Images"); | |
Guard.ForDuplicates(tagIds, "Tags"); | |
var fabric = new Fabric(); | |
if (preOrder) | |
{ | |
if (due.HasNoValue) | |
{ | |
throw new InvalidOperationException("A pre ordered fabric must have due set"); | |
} | |
fabric.SetPreOrder(due.Value); | |
} | |
else | |
{ | |
if (due.HasValue) | |
{ | |
throw new InvalidOperationException("A pre ordered fabric does not need a due set"); | |
} | |
} | |
fabric._Images = imageIds | |
.Select(id => new FabricImage(fabric.Id, id)) | |
.ToList(); | |
fabric.MakeFirstImageDefault(); | |
fabric._Tags = tagIds | |
.Select(id => new FabricTag(fabric.Id, id)) | |
.ToList(); | |
return fabric; | |
} | |
private void SetPreOrder(string due) | |
{ | |
PreOrder = true; | |
Due = due; | |
} | |
private void HasArrived() | |
{ | |
PreOrder = false; | |
Due = null; | |
} | |
private void MakeFirstImageDefault() | |
{ | |
FabricImage firstImage = _Images.FirstOrDefault(); | |
if (firstImage != null) | |
{ | |
firstImage.SetIsDefault(true); | |
} | |
} | |
internal void Update(Fabric update) | |
{ | |
if (update.PreOrder) | |
{ | |
SetPreOrder(update.Due.Value); | |
} | |
else | |
{ | |
HasArrived(); | |
} | |
UpdateLinkedObjects(_Tags, update.Tags, AddFabricTag); | |
UpdateLinkedObjects(_Images, update.Images, AddFabricImage); | |
UpdateDefaultImage(update); | |
} | |
private void UpdateDefaultImage(Fabric update) | |
{ | |
int? newDefaultImageId = update.GetDefaultImageId(); | |
if (newDefaultImageId == null) | |
return; | |
Maybe<FabricImage> oldDefaultImageOrNothing = GetDefaultImage(); | |
if (oldDefaultImageOrNothing.HasValue) | |
{ | |
var oldDefaultImage = oldDefaultImageOrNothing.Value; | |
if (oldDefaultImage.ImageId == newDefaultImageId) | |
return; | |
oldDefaultImage.SetIsDefault(false); | |
} | |
var newDefaultImage = _Images.SingleOrDefault(i => i.ImageId == newDefaultImageId); | |
newDefaultImage.SetIsDefault(true); | |
} | |
public Maybe<FabricImage> GetDefaultImage() | |
{ | |
return _Images.SingleOrDefault(i => i.IsDefault); | |
} | |
internal int? GetDefaultImageId() | |
{ | |
if (_Images.Count > 0) | |
{ | |
return GetDefaultImage().Value.ImageId; | |
} | |
return null; | |
} | |
private void AddFabricImage(int fabricId, int imageId) | |
{ | |
var fabricImage = new FabricImage(fabricId, imageId); | |
_Images.Add(fabricImage); | |
} | |
private void AddFabricTag(int fabricId, int tagId) | |
{ | |
var fabricTag = new FabricTag(fabricId, tagId); | |
_Tags.Add(fabricTag); | |
} | |
} | |
public abstract class AggregateRootWithLinkedObjects : AggregateRoot<int> | |
{ | |
/// <summary> | |
/// This method should not be accessible outside its class. It has to be because there is no way to have internal and | |
/// protected at the same time (or is allowed) | |
/// </summary> | |
internal void UpdateLinkedObjects<T>(IEnumerable<ILinkToAggregate<T>> linkedObjectsToUpdate, | |
IEnumerable<ILinkToAggregate<T>> updates, | |
Action<int, int> addNewLinkedObjectToCollection) | |
{ | |
IReadOnlyList<int> newLinkedObjectIds = GetIdsFromLinkedObjects(updates); | |
UpdateLinkedObjects(linkedObjectsToUpdate, newLinkedObjectIds, addNewLinkedObjectToCollection); | |
} | |
/// <summary> | |
/// This method should not be accessible outside its class. | |
/// </summary> | |
internal void UpdateLinkedObjects<T>(IEnumerable<ILinkToAggregate<T>> linkedObjectsToUpdate, | |
IReadOnlyList<int> newLinkedObjectIds, | |
Action<int, int> addNewLinkedObjectToCollection) | |
{ | |
IReadOnlyList<int> oldLinkedObjectIds = GetIdsFromLinkedObjects(linkedObjectsToUpdate); | |
IEnumerable<ILinkToAggregate<T>> linkedObjectsToDelete = GetLinkedObjectsToDelete(linkedObjectsToUpdate, newLinkedObjectIds); | |
IEnumerable<ILinkToAggregate<T>> linkedObjectsToKeep = linkedObjectsToUpdate.Except(linkedObjectsToDelete); | |
IEnumerable<int> linkedObjectIdsToAdd = newLinkedObjectIds.Except(oldLinkedObjectIds); | |
MarkLinkedObjectsForDeletion(linkedObjectsToDelete); | |
MarkLinkedObjectsForKeeping(linkedObjectsToKeep); | |
CreateAndAddNewLinkedObjects<T>(linkedObjectIdsToAdd, addNewLinkedObjectToCollection); | |
} | |
private IReadOnlyList<int> GetIdsFromLinkedObjects<T>(IEnumerable<ILinkToAggregate<T>> linkedObjects) | |
{ | |
return linkedObjects.Select(t => t.LinkedObjectId).ToList(); | |
} | |
private IEnumerable<ILinkToAggregate<T>> GetLinkedObjectsToDelete<T>(IEnumerable<ILinkToAggregate<T>> linkedObjectsToUpdate, IReadOnlyList<int> newLinkedObjectIds) | |
{ | |
return linkedObjectsToUpdate.Where(t => !newLinkedObjectIds.Contains(t.LinkedObjectId)); | |
} | |
private void MarkLinkedObjectsForDeletion<T>(IEnumerable<ILinkToAggregate<T>> linkedObjectsToDelete) | |
{ | |
foreach (ILinkToAggregate<T> linkedObject in linkedObjectsToDelete) | |
{ | |
linkedObject.State = ObjectState.Deleted; | |
} | |
} | |
private void MarkLinkedObjectsForKeeping<T>(IEnumerable<ILinkToAggregate<T>> linkedObjectsToKeep) | |
{ | |
foreach (ILinkToAggregate<T> linkedObject in linkedObjectsToKeep) | |
{ | |
linkedObject.State = ObjectState.Unchanged; | |
} | |
} | |
private void CreateAndAddNewLinkedObjects<T>(IEnumerable<int> linkedObjectIdsToAdd, | |
Action<int, int> addNewLinkedObjectToCollection) | |
{ | |
foreach (int linkedObjectId in linkedObjectIdsToAdd) | |
{ | |
addNewLinkedObjectToCollection(Id, linkedObjectId); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment