/// <summary> /// Save (insert/update) a Widget into the store /// </summary> /// <param name="entitiesBeingHandled">Entities already being saved further up the save stack</param> /// <param name="widgets">The Widgets to save</param> /// <param name="toSave">Entity types to cascade to, if they are loaded</param> internal void Save(List <Entity> entitiesBeingHandled, Flags toSave, params Widget[] widgets) { if (widgets == null) { throw new ArgumentNullException("widgets"); } Log("Save", widgets.Select <Widget, int>(entity => entity.Identity).ToArray <int>(), EntityType.None); // Copy the list of entities being handled, and add this new set of entities to it. // We're handling those now. List <Entity> entitiesNowBeingHandled = new List <Entity>(entitiesBeingHandled); entitiesNowBeingHandled.AddRange(widgets); // Loop over each entity and save it. foreach (Widget widget in widgets) { // Already being saved higher up the stack? if (entitiesBeingHandled.ContainsEntity(widget)) { continue; } // Allow derived/partial class to do extra work OnBeforeSaveEntity(widget); // Save parent entity... so we can update our key to it if ((toSave & EntityType.Thing) == EntityType.Thing && widget.ThingPopulated) { if (!entitiesBeingHandled.ContainsEntity(widget.Thing)) { ThingRepo.Save(entitiesNowBeingHandled, toSave, widget.Thing); widget.ThingId = widget.Thing.Identity; } } bool saved = false; try { // Save the entity if (widget.IsNew) { this.Mapper.Insert("InsertWidget", widget); saved = true; } else if (widget.IsChanged) { if (this.Mapper.Update("UpdateWidget", widget) != 1) { ThrowWidgetEntityException(widget.Identity); } saved = true; } } catch (Exception ex) { throw EntityLogger.WriteUnexpectedException( ex, "Failed to insert/update Entity", Category.EntityFramework, widget); } // Save child entities... update their key to us if ((toSave & EntityType.FieldTest) == EntityType.FieldTest && widget.FieldTestListUsingForeignKeyFieldPopulated) { foreach (FieldTest childFieldTest in widget.FieldTestListUsingForeignKeyField) { childFieldTest.ForeignKeyField = widget.Identity; if (!entitiesBeingHandled.ContainsEntity(childFieldTest)) { if (childFieldTest.IsDeleted) { FieldTestRepo.Delete(entitiesNowBeingHandled, toSave, childFieldTest); } else { FieldTestRepo.Save(entitiesNowBeingHandled, toSave, childFieldTest); } } } } // Save child entities... update their key to us if ((toSave & EntityType.FieldTest) == EntityType.FieldTest && widget.FieldTestListUsingForeignKeyFieldNullablePopulated) { foreach (FieldTest childFieldTest in widget.FieldTestListUsingForeignKeyFieldNullable) { childFieldTest.ForeignKeyFieldNullable = widget.Identity; if (!entitiesBeingHandled.ContainsEntity(childFieldTest)) { if (childFieldTest.IsDeleted) { FieldTestRepo.Delete(entitiesNowBeingHandled, toSave, childFieldTest); } else { FieldTestRepo.Save(entitiesNowBeingHandled, toSave, childFieldTest); } } } } // Post save protocol if (saved) { // Allow derived/partial class to do extra work OnAfterSaveEntity(widget); widget.Reset(); //The insert/update will have resulted in a new database_update row, inform interested parties RaiseModelChanged(); } } }
/// <summary> /// Populate the sub entities of widgetList /// </summary> /// <param name="widgets"></param> /// <param name="toPopulate"></param> public override void Populate(IEnumerable <Widget> widgets, Flags toPopulate) { Log("Populate", widgets.GetIdenties(), toPopulate); // Implement breadth first loading of related entities. // Any entity that has been requested to be loaded, should be loaded at this level where possible. // Remove all sub entity types that this entity relates to directly. Flags stillToPopulate = toPopulate; stillToPopulate = stillToPopulate.Remove(EntityType.FieldTest); stillToPopulate = stillToPopulate.Remove(EntityType.FieldTest); stillToPopulate = stillToPopulate.Remove(EntityType.Thing); // Get sub entities: FieldTest if ((toPopulate & EntityType.FieldTest) == EntityType.FieldTest) { // Grab the ones that actually need populating IEnumerable <Widget> toBePopulated = widgets.Where(entity => entity.FieldTestListUsingForeignKeyFieldPopulated == false); // And load the sub entities for those ones. FieldTestList childFieldTestList = toBePopulated.Count() > 0 ? FieldTestRepo.GetByForeignKeyField( toBePopulated.GetIdenties(), stillToPopulate) : new FieldTestList(); Dictionary <int, List <FieldTest> > fieldTestListByForeignKeyField = childFieldTestList.MapByForeignKeyField; // Now go over all the entites. For ones that need popualting, populate collection // directly. For those already populated, make a check on sub entities to ensure // they are loaded to the required level FieldTestList toBeChecked = new FieldTestList(); foreach (Widget widget in widgets) { if (!widget.FieldTestListUsingForeignKeyFieldPopulated) { var FieldTestListsForWidget = fieldTestListByForeignKeyField.ContainsKey(widget.Identity) ? fieldTestListByForeignKeyField[widget.Identity] : null; if (FieldTestListsForWidget != null) { FieldTestListsForWidget.ForEach(entity => entity.ForeignKeyFieldWidget = widget); } widget.PopulateFieldTestListUsingForeignKeyField(FieldTestListsForWidget); } else { toBeChecked.AddRange(widget.FieldTestListUsingForeignKeyField); } } // If there's any "to be checked" (because they were already loaded) let the entities own // repo do whatever checks it needs to do if (toBeChecked.Count > 0) { FieldTestRepo.Populate(toBeChecked, stillToPopulate); } } // Get sub entities: FieldTest if ((toPopulate & EntityType.FieldTest) == EntityType.FieldTest) { // Grab the ones that actually need populating IEnumerable <Widget> toBePopulated = widgets.Where(entity => entity.FieldTestListUsingForeignKeyFieldNullablePopulated == false); // And load the sub entities for those ones. FieldTestList childFieldTestList = toBePopulated.Count() > 0 ? FieldTestRepo.GetByForeignKeyFieldNullable( toBePopulated.GetIdenties().Select(i => new Nullable <int>(i)).ToArray(), stillToPopulate) : new FieldTestList(); Dictionary <int?, List <FieldTest> > fieldTestListByForeignKeyFieldNullable = childFieldTestList.MapByForeignKeyFieldNullable; // Now go over all the entites. For ones that need popualting, populate collection // directly. For those already populated, make a check on sub entities to ensure // they are loaded to the required level FieldTestList toBeChecked = new FieldTestList(); foreach (Widget widget in widgets) { if (!widget.FieldTestListUsingForeignKeyFieldNullablePopulated) { var FieldTestListsForWidget = fieldTestListByForeignKeyFieldNullable.ContainsKey(widget.Identity) ? fieldTestListByForeignKeyFieldNullable[widget.Identity] : null; if (FieldTestListsForWidget != null) { FieldTestListsForWidget.ForEach(entity => entity.ForeignKeyFieldNullableWidget = widget); } widget.PopulateFieldTestListUsingForeignKeyFieldNullable(FieldTestListsForWidget); } else { toBeChecked.AddRange(widget.FieldTestListUsingForeignKeyFieldNullable); } } // If there's any "to be checked" (because they were already loaded) let the entities own // repo do whatever checks it needs to do if (toBeChecked.Count > 0) { FieldTestRepo.Populate(toBeChecked, stillToPopulate); } } // Get parent entities: Thing if ((toPopulate & EntityType.Thing) == EntityType.Thing) { // Grab the ids for the ones that actually need populating IEnumerable <Widget> toBePopulated = widgets.Where(entity => entity.ThingRequiresPopulation); int[] idsToLoad = toBePopulated.Select(entity => entity.ThingId).ToList().ToArray(); // And load the sub entities for those ones. ThingList parentThingList = toBePopulated.Count() > 0 ? ThingRepo.Get(idsToLoad, stillToPopulate) : new ThingList(); Dictionary <int, Thing> thingListById = parentThingList.MapById; // Now go over all the entites. For ones that need popualting, populate entities // directly. For those already populated, make a check on sub entities to ensure // they are loaded to the required level ThingList toBeChecked = new ThingList(); foreach (Widget widget in widgets) { if (widget.ThingRequiresPopulation) { widget.Thing = thingListById.ContainsKey(widget.ThingId) ? thingListById[widget.ThingId] : null; } else if (widget.ThingPopulated) { toBeChecked.Add(widget.Thing); } } // If there's any "to be checked" (because they were already loaded) let the entiies own // repo do whatever checks it needs to do if (toBeChecked.Count > 0) { ThingRepo.Populate(toBeChecked, stillToPopulate); } } }
/// <summary> /// Delete Widget entities from the store, including sub entites marked for deletion /// </summary> /// <param name="entitiesBeingHandled">Entities already being deleted further up the delete stack</param> /// <param name="widgets">The Widgets to delete</param> /// <param name="toDelete">Entity types to cascade to, if they are loaded</param> internal void Delete(List <Entity> entitiesBeingHandled, Flags toDelete, IEnumerable <Widget> widgets) { if (widgets == null) { throw new ArgumentNullException("widgets"); } Log("Delete", widgets.Select <Widget, int>(entity => entity.Identity).ToArray <int>(), EntityType.None); // Copy the list of entities being handled, and add this new set of entities to it. // We're handling those now. List <Entity> entitiesNowBeingHandled = new List <Entity>(entitiesBeingHandled); entitiesNowBeingHandled.AddRange(widgets); // Loop over each entity and delete it. foreach (Widget widget in widgets) { // Already being deleted higher up the stack? if (entitiesBeingHandled.ContainsEntity(widget)) { continue; } //Allow partial/subclasses to perform additional processing OnBeforeDeleteEntity(widget); // Delete child entities if ((toDelete & EntityType.FieldTest) == EntityType.FieldTest && widget.FieldTestListUsingForeignKeyFieldPopulated) { foreach (FieldTest childFieldTest in widget.FieldTestListUsingForeignKeyField) { if (!entitiesBeingHandled.ContainsEntity(childFieldTest)) { FieldTestRepo.Delete(entitiesNowBeingHandled, toDelete, childFieldTest); } } } // Delete child entities if ((toDelete & EntityType.FieldTest) == EntityType.FieldTest && widget.FieldTestListUsingForeignKeyFieldNullablePopulated) { foreach (FieldTest childFieldTest in widget.FieldTestListUsingForeignKeyFieldNullable) { if (!entitiesBeingHandled.ContainsEntity(childFieldTest)) { FieldTestRepo.Delete(entitiesNowBeingHandled, toDelete, childFieldTest); } } } // Now delete the entity if (this.Mapper.Delete("DeleteWidget", widget.Identity) != 1) { ThrowWidgetEntityException(widget.Identity); } widget.ResetChanged(); //Allow partial/subclasses to perform additional processing OnAfterDeleteEntity(widget); } //Save to the repository updates table if (widgets.Count() > 0) { RaiseModelChanged(); } }