/// <summary> /// Populate the sub entities of fieldTestList /// </summary> /// <param name="fieldTests"></param> /// <param name="toPopulate"></param> public override void Populate(IEnumerable <FieldTest> fieldTests, Flags toPopulate) { Log("Populate", fieldTests.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.Widget); stillToPopulate = stillToPopulate.Remove(EntityType.Widget); // Get parent entities: Widget if ((toPopulate & EntityType.Widget) == EntityType.Widget) { // Grab the ids for the ones that actually need populating IEnumerable <FieldTest> toBePopulated = fieldTests.Where(entity => entity.ForeignKeyFieldWidgetRequiresPopulation); int[] idsToLoad = toBePopulated.Select(entity => entity.ForeignKeyField).ToList().ToArray(); // And load the sub entities for those ones. WidgetList parentWidgetList = toBePopulated.Count() > 0 ? WidgetRepo.Get(idsToLoad, stillToPopulate) : new WidgetList(); Dictionary <int, Widget> widgetListById = parentWidgetList.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 WidgetList toBeChecked = new WidgetList(); foreach (FieldTest fieldTest in fieldTests) { if (fieldTest.ForeignKeyFieldWidgetRequiresPopulation) { fieldTest.ForeignKeyFieldWidget = widgetListById.ContainsKey(fieldTest.ForeignKeyField) ? widgetListById[fieldTest.ForeignKeyField] : null; } else if (fieldTest.ForeignKeyFieldWidgetPopulated) { toBeChecked.Add(fieldTest.ForeignKeyFieldWidget); } } // 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) { WidgetRepo.Populate(toBeChecked, stillToPopulate); } } // Get parent entities: Widget if ((toPopulate & EntityType.Widget) == EntityType.Widget) { // Grab the ids for the ones that actually need populating IEnumerable <FieldTest> toBePopulated = fieldTests.Where(entity => entity.ForeignKeyFieldNullableWidgetRequiresPopulation); int[] idsToLoad = toBePopulated.Select(entity => entity.ForeignKeyFieldNullable.Value).ToList().ToArray(); // And load the sub entities for those ones. WidgetList parentWidgetList = toBePopulated.Count() > 0 ? WidgetRepo.Get(idsToLoad, stillToPopulate) : new WidgetList(); Dictionary <int, Widget> widgetListById = parentWidgetList.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 WidgetList toBeChecked = new WidgetList(); foreach (FieldTest fieldTest in fieldTests) { if (fieldTest.ForeignKeyFieldNullableWidgetRequiresPopulation) { fieldTest.ForeignKeyFieldNullableWidget = widgetListById.ContainsKey(fieldTest.ForeignKeyFieldNullable.Value) ? widgetListById[fieldTest.ForeignKeyFieldNullable.Value] : null; } else if (fieldTest.ForeignKeyFieldNullableWidgetPopulated) { toBeChecked.Add(fieldTest.ForeignKeyFieldNullableWidget); } } // 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) { WidgetRepo.Populate(toBeChecked, stillToPopulate); } } }
/// <summary> /// Save (insert/update) a Thing into the store /// </summary> /// <param name="entitiesBeingHandled">Entities already being saved further up the save stack</param> /// <param name="things">The Things 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 Thing[] things) { if (things == null) { throw new ArgumentNullException("things"); } Log("Save", things.Select <Thing, 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(things); // Loop over each entity and save it. foreach (Thing thing in things) { // Already being saved higher up the stack? if (entitiesBeingHandled.ContainsEntity(thing)) { continue; } // Allow derived/partial class to do extra work OnBeforeSaveEntity(thing); bool saved = false; try { // Save the entity if (thing.IsNew) { this.Mapper.Insert("InsertThing", thing); saved = true; } else if (thing.IsChanged) { if (this.Mapper.Update("UpdateThing", thing) != 1) { ThrowThingEntityException(thing.Identity); } saved = true; } } catch (Exception ex) { throw EntityLogger.WriteUnexpectedException( ex, "Failed to insert/update Entity", Category.EntityFramework, thing); } // Save child entities... update their key to us if ((toSave & EntityType.Widget) == EntityType.Widget && thing.WidgetListPopulated) { foreach (Widget childWidget in thing.WidgetList) { childWidget.ThingId = thing.Identity; if (!entitiesBeingHandled.ContainsEntity(childWidget)) { if (childWidget.IsDeleted) { WidgetRepo.Delete(entitiesNowBeingHandled, toSave, childWidget); } else { WidgetRepo.Save(entitiesNowBeingHandled, toSave, childWidget); } } } } // Post save protocol if (saved) { // Allow derived/partial class to do extra work OnAfterSaveEntity(thing); thing.Reset(); //The insert/update will have resulted in a new database_update row, inform interested parties RaiseModelChanged(); } } }
/// <summary> /// Save (insert/update) a FieldTest into the store /// </summary> /// <param name="entitiesBeingHandled">Entities already being saved further up the save stack</param> /// <param name="fieldTests">The FieldTests 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 FieldTest[] fieldTests) { if (fieldTests == null) { throw new ArgumentNullException("fieldTests"); } Log("Save", fieldTests.Select <FieldTest, 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(fieldTests); // Loop over each entity and save it. foreach (FieldTest fieldTest in fieldTests) { // Already being saved higher up the stack? if (entitiesBeingHandled.ContainsEntity(fieldTest)) { continue; } // Allow derived/partial class to do extra work OnBeforeSaveEntity(fieldTest); // Save parent entity... so we can update our key to it if ((toSave & EntityType.Widget) == EntityType.Widget && fieldTest.ForeignKeyFieldWidgetPopulated) { if (!entitiesBeingHandled.ContainsEntity(fieldTest.ForeignKeyFieldWidget)) { WidgetRepo.Save(entitiesNowBeingHandled, toSave, fieldTest.ForeignKeyFieldWidget); fieldTest.ForeignKeyField = fieldTest.ForeignKeyFieldWidget.Identity; } } // Save parent entity... so we can update our key to it if ((toSave & EntityType.Widget) == EntityType.Widget && fieldTest.ForeignKeyFieldNullableWidgetPopulated) { if (!entitiesBeingHandled.ContainsEntity(fieldTest.ForeignKeyFieldNullableWidget)) { WidgetRepo.Save(entitiesNowBeingHandled, toSave, fieldTest.ForeignKeyFieldNullableWidget); fieldTest.ForeignKeyFieldNullable = fieldTest.ForeignKeyFieldNullableWidget.Identity; } } bool saved = false; try { // Save the entity if (fieldTest.IsNew) { this.Mapper.Insert("InsertFieldTest", fieldTest); saved = true; } else if (fieldTest.IsChanged) { if (this.Mapper.Update("UpdateFieldTest", fieldTest) != 1) { ThrowFieldTestEntityException(fieldTest.Identity); } saved = true; } } catch (Exception ex) { throw EntityLogger.WriteUnexpectedException( ex, "Failed to insert/update Entity", Category.EntityFramework, fieldTest); } // Post save protocol if (saved) { // Allow derived/partial class to do extra work OnAfterSaveEntity(fieldTest); fieldTest.Reset(); //The insert/update will have resulted in a new database_update row, inform interested parties RaiseModelChanged(); } } }