/// <summary> /// Validates a single entity. /// Skips validation (returns true) if entity is marked Deleted. /// </summary> /// <param name="entityInfo">contains the entity to validate</param> /// <param name="entityErrors">An EntityError is added to this list for each error found in the entity</param> /// <returns>true if entity is valid, false if invalid.</returns> public bool ValidateEntity(EntityInfo entityInfo, List<EntityError> entityErrors) { if (entityInfo.EntityState == EntityState.Deleted) return true; bool isValid = true; var entity = entityInfo.Entity; var entityType = entity.GetType(); var entityTypeName = entityType.FullName; var sType = _structuralTypeMap[entityTypeName]; var dataProperties = sType.dataProperties; object[] keyValues = null; foreach (var dp in sType.dataProperties) { if (dp.validators == null) continue; if (dp.propertyInfo == null) { dp.propertyInfo = entityType.GetProperty(dp.name); // try converting from camelCase? if (dp.propertyInfo == null) continue; } var value = dp.propertyInfo.GetValue(entity, null); foreach (var validator in dp.validators) { var errorMessage = validator.Validate(value); if (errorMessage != null) { if (keyValues == null) keyValues = _contextProvider.GetKeyValues(entityInfo); entityErrors.Add(new EntityError() { EntityTypeName = entityTypeName, ErrorMessage = errorMessage, ErrorName = "ValidationError", KeyValues = keyValues, PropertyName = dp.name }); isValid = false; } } } return isValid; }
public override bool BeforeSaveEntity(EntityInfo entityInfo) { // prohibit any additions of entities of type 'Role' if (entityInfo.Entity.GetType() == typeof(Role) && entityInfo.EntityState == EntityState.Added) { return false; } else { return true; } }
// Todo: delegate to helper classes when it gets more complicated protected override bool BeforeSaveEntity(EntityInfo entityInfo) { var entity = entityInfo.Entity; if (entity is TodoList) { return true; } if (entity is TodoItem) { return BeforeSaveTodoItem(entity as TodoItem, entityInfo); } throw new InvalidOperationException("Cannot save entity of unknown type"); }
protected override bool BeforeSaveEntity(Breeze.WebApi.EntityInfo entityInfo) { if (entityInfo.Entity is AnnouncementModel) { var announcementModel = (AnnouncementModel)entityInfo.Entity; if (announcementModel != null) { announcementModel.AnnouncementDate = DateTime.Now; } } if (entityInfo.Entity is StaffModel) { var staffModel = (StaffModel)entityInfo.Entity; if (staffModel != null) { staffModel = BreezeDataController.ValidateStaffModel(staffModel); } } else if (entityInfo.Entity is StaffLeaveModel) { var leave = (StaffLeaveModel)entityInfo.Entity; if (leave != null) { leave = BreezeDataController.ValidateLeaveApplication(leave); } } else if (entityInfo.Entity is StaffLeaveCounterModel) { StaffLeaveCounterModel leaveCounter = (StaffLeaveCounterModel)entityInfo.Entity; if (leaveCounter != null) { leaveCounter = BreezeDataController.ValidateLeaveCounterModel(leaveCounter); } } //else if (entityInfo.Entity is StaffClockModel) //{ // StaffClockModel clockData = (StaffClockModel)entityInfo.Entity; // if (clockData != null) // { // clockData = BreezeDataController.ValidateClockModel(clockData); // } //} return(base.BeforeSaveEntity(entityInfo)); }
/// <summary> /// True if can save this entity else throw exception /// </summary> /// <exception cref="System.InvalidOperationException"></exception> public bool BeforeSaveEntity(EntityInfo arg) { var typeName = arg.Entity.GetType().Name; var saveError = string.Empty; var saveable = arg.Entity as ISaveable; if (UserStoreId == Guid.Empty) { saveError = "you are not authorized to save."; } else if (saveable == null) { saveError = "changes to '" + typeName + "' are forbidden."; } else { switch (arg.EntityState) { case EntityState.Added: saveable.StoreId = UserStoreId; arg.OriginalValuesMap.Add("StoreId", UserStoreId); saveError = saveable.CanAdd(); break; case EntityState.Modified: case EntityState.Deleted: saveError = CanSaveExistingEntity(arg); break; default: var stateName = Enum.GetName(typeof(EntityState), arg.EntityState); saveError = " unexpected EntityState of " + stateName; break; } } if (saveError != null) { throw new InvalidOperationException( "'" + arg.Entity.GetType().Name + "' may not be saved because " + saveError); } return true; }
/// <summary> /// Add the relationship to the dependencyGraph /// </summary> /// <param name="child">Entity that depends on parent (e.g. has a many-to-one relationship to parent)</param> /// <param name="parent">Entity that child depends on (e.g. one parent has one-to-many children)</param> /// <param name="removeReverse">True to find and remove the reverse relationship. Used for handling one-to-ones.</param> private void AddToGraph(EntityInfo child, EntityInfo parent, bool removeReverse) { List<EntityInfo> list; if (!dependencyGraph.TryGetValue(child, out list)) { list = new List<EntityInfo>(5); dependencyGraph.Add(child, list); } if (parent != null) list.Add(parent); if (removeReverse) { List<EntityInfo> parentList; if (dependencyGraph.TryGetValue(parent, out parentList)) { parentList.Remove(child); } } }
/// <summary> /// Validates a single entity. /// Skips validation (returns true) if entity is marked Deleted. /// </summary> /// <param name="entityInfo">contains the entity to validate</param> /// <param name="entityErrors">An EntityError is added to this list for each error found in the entity</param> /// <returns>true if entity is valid, false if invalid.</returns> public bool ValidateEntity(EntityInfo entityInfo, List<EntityError> entityErrors) { if (entityInfo.EntityState == EntityState.Deleted) return true; // Perform validation on the entity, based on DataAnnotations. var entity = entityInfo.Entity; var validationResults = new List<ValidationResult>(); if (!Validator.TryValidateObject(entity, new ValidationContext(entity, null, null), validationResults, true)) { var keyValues = _contextProvider.GetKeyValues(entityInfo); var entityTypeName = entity.GetType().FullName; foreach (var vr in validationResults) { entityErrors.Add(new EntityError() { EntityTypeName = entityTypeName, ErrorMessage = vr.ErrorMessage, ErrorName = "ValidationError", KeyValues = keyValues, PropertyName = vr.MemberNames.FirstOrDefault() }); } return false; } return true; }
private bool BefoueSaveEntity(EntityInfo arg) { var entity = arg.Entity; //var type = arg. return true; }
public TempKeyInfo(EntityInfo entityInfo) { _entityInfo = entityInfo; }
private string CanSaveExistingEntity(EntityInfo arg) { var type = arg.Entity.GetType(); if (type == typeof(Customer)) { return ExistingCustomerSaveGuard(arg); } if (type == typeof(Order)) { return ExistingOrderSaveGuard(arg); } if (type == typeof(OrderItem)) { return ExistingOrderItemSaveGuard(arg); } if (type == typeof(OrderItemOption)) { return ExistingOrderItemOptionSaveGuard(arg); } return "is not a saveable type"; }
public bool BeforeSaveEntity(Breeze.WebApi.EntityInfo entityInfo) { return(true); }
private string ExistingOrderItemOptionSaveGuard(EntityInfo arg) { var entity = (OrderItemOption)arg.Entity; var orig = readContext.OrderItemOptions.SingleOrDefault(e => e.Id == entity.Id); return ExistingEntityGuard(orig, entity.Id); }
private bool BeforeSaveToDoItem(ToDoItem todoItem, EntityInfo info) { var todoList = Context.ToDoLists.FirstOrDefault( l => l.ToDoListId == todoItem.ToDoListId); return (null == todoList) ? throwCannotFindParentToDoList() : UserId == todoList.UserId || throwCannotSaveEntityForThisUser(); }
public virtual object[] GetKeyValues(EntityInfo entityInfo) { throw new NotImplementedException(); }
private string ExistingOrderSaveGuard(EntityInfo arg) { var entity = (Order)arg.Entity; var orig = readContext.Orders.SingleOrDefault(e => e.OrderID == entity.OrderID); return ExistingEntityGuard(orig, entity.OrderID); }
private string CanSaveExistingEntity(EntityInfo arg) { var type = arg.Entity.GetType(); if (type == typeof(Customer)) { return ExistingCustomerSaveGuard(arg); } if (type == typeof(Employee)) { return ExistingEmployeeSaveGuard(arg); } if (type == typeof(Order)) { return ExistingOrderSaveGuard(arg); } if (type == typeof(OrderDetail)) { return ExistingOrderDetailSaveGuard(arg); } if (type == typeof(InternationalOrder)) { return ExistingInternationalOrderSaveGuard(arg); } if (type == typeof(User)) { return ExistingUserSaveGuard(arg); } return "is is not a saveable type"; }
/// <summary> /// The method is called for each entity to be saved before the save occurs. If this method returns 'false' /// then the entity will be excluded from the save. There is no need to call the base implementation of this /// method when overriding it. /// </summary> /// <param name="entityInfo"></param> /// <returns></returns> protected internal virtual bool BeforeSaveEntity(EntityInfo entityInfo) { if (BeforeSaveEntityDelegate != null) { return BeforeSaveEntityDelegate(entityInfo); } else { return true; } }
private string ExistingEmployeeSaveGuard(EntityInfo arg) { var entity = (Employee)arg.Entity; var orig = readContext.Employees.SingleOrDefault(e => e.EmployeeID == entity.EmployeeID); return ExistingEntityGuard(orig, entity.EmployeeID); }
private bool BeforeSaveTodoItem(TodoItem todoItem, EntityInfo info) { var todoList = Context.TodoLists.FirstOrDefault(tl => tl.TodoListId == todoItem.TodoListId); return (null != todoList) || throwCannotFindParentTodoList(); }
/// <summary> /// Get a related entity based on the value of the foreign key. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> /// <param name="canUseSession">Whether we can load the related entity via the Session. /// If false, we only connect entities that are also in the saveMap</param> /// <returns></returns> private object GetRelatedEntity(string propName, IType propType, EntityInfo entityInfo, IClassMetadata meta, bool canUseSession) { object relatedEntity = null; var relKey = meta.EntityName + '.' + propName; var foreignKeyName = fkMap[relKey]; object id = GetForeignKeyValue(entityInfo, meta, foreignKeyName, canUseSession); if (id != null) { relatedEntity = FindInSaveMap(propType.ReturnedClass, id); if (relatedEntity == null && canUseSession) { var relatedEntityName = propType.Name; relatedEntity = session.Load(relatedEntityName, id); } } return relatedEntity; }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> /// <param name="canUseSession">Whether we can load the related entity via the Session. /// If false, we only connect entities that are also in the saveMap</param> private void FixupRelationship(string propName, IType propType, EntityInfo entityInfo, IClassMetadata meta, bool canUseSession) { var entity = entityInfo.Entity; object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) return; // entities are already connected relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta, canUseSession); if (relatedEntity != null) meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); }
private bool BeforeSaveToDoList(ToDoList todoList, EntityInfo info) { if (info.EntityState == EntityState.Added) { todoList.UserId = UserId; return true; } return UserId == todoList.UserId || throwCannotSaveEntityForThisUser(); }
private ObjectStateEntry HandleDeletedPart1(EntityInfo entityInfo) { return(null); }
/// <summary> /// Recursively add entities to the saveOrder or deleteOrder according to their dependencies /// </summary> /// <param name="entityInfo">Entity to be added. Its dependencies will be added depth-first.</param> /// <param name="depth">prevents infinite recursion in case of cyclic dependencies</param> private void AddToSaveOrder(EntityInfo entityInfo, int depth) { if (saveOrder.Contains(entityInfo)) return; if (deleteOrder.Contains(entityInfo)) return; if (depth > 10) return; var dependencies = dependencyGraph[entityInfo]; foreach (var dep in dependencies) { AddToSaveOrder(dep, depth + 1); } if (entityInfo.EntityState == EntityState.Deleted) deleteOrder.Add(entityInfo); else saveOrder.Add(entityInfo); }
/// <summary> /// Connect the related entities based on the foreign key values. /// Note that this may cause related entities to be loaded from the DB if they are not already in the session. /// </summary> /// <param name="entityInfo">Entity that will be saved</param> /// <param name="meta">Metadata about the entity type</param> private void FixupRelationships(EntityInfo entityInfo, IClassMetadata meta) { var propNames = meta.PropertyNames; var propTypes = meta.PropertyTypes; if (meta.IdentifierType != null) { var propType = meta.IdentifierType; if (propType.IsAssociationType && propType.IsEntityType) { FixupRelationship(meta.IdentifierPropertyName, (EntityType)propType, entityInfo, meta); } else if (propType.IsComponentType) { FixupComponentRelationships(meta.IdentifierPropertyName, (ComponentType)propType, entityInfo, meta); } } for (int i = 0; i < propNames.Length; i++) { var propType = propTypes[i]; if (propType.IsAssociationType && propType.IsEntityType) { FixupRelationship(propNames[i], (EntityType)propTypes[i], entityInfo, meta); } else if (propType.IsComponentType) { FixupComponentRelationships(propNames[i], (ComponentType)propType, entityInfo, meta); } } }
private string ExistingOrderDetailSaveGuard(EntityInfo arg) { var entity = (OrderDetail)arg.Entity; var orig = readContext.OrderDetails .SingleOrDefault(e => e.OrderID == entity.OrderID && e.ProductID == entity.ProductID); var key = "(" + entity.OrderID + "," + entity.ProductID + ")"; return ExistingEntityGuard(orig, key); }
/// <summary> /// Connect the related entities based on the foreign key values found in a component type. /// This updates the values of the component's properties. /// </summary> /// <param name="propName">Name of the (component) property of the entity. May be null if the property is the entity's identifier.</param> /// <param name="compType">Type of the component</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupComponentRelationships(string propName, ComponentType compType, EntityInfo entityInfo, IClassMetadata meta) { var compPropNames = compType.PropertyNames; var compPropTypes = compType.Subtypes; object component = null; object[] compValues = null; bool isChanged = false; for (int j = 0; j < compPropNames.Length; j++) { var compPropType = compPropTypes[j]; if (compPropType.IsAssociationType && compPropType.IsEntityType) { if (compValues == null) { // get the value of the component's subproperties component = GetPropertyValue(meta, entityInfo.Entity, propName); compValues = compType.GetPropertyValues(component, EntityMode.Poco); } if (compValues[j] == null) { // the related entity is null var relatedEntity = GetRelatedEntity(compPropNames[j], (EntityType)compPropType, entityInfo, meta); if (relatedEntity != null) { compValues[j] = relatedEntity; isChanged = true; } } else if (removeMode) { // remove the relationship compValues[j] = null; isChanged = true; } } } if (isChanged) { compType.SetPropertyValues(component, compValues, EntityMode.Poco); } }
private string ExistingUserSaveGuard(EntityInfo arg) { var entity = (User)arg.Entity; var orig = readContext.Users.SingleOrDefault(e => e.Id == entity.Id); return ExistingEntityGuard(orig, entity.Id); }
/// <summary> /// Set an association value based on the value of the foreign key. This updates the property of the entity. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> private void FixupRelationship(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { var entity = entityInfo.Entity; if (removeMode) { meta.SetPropertyValue(entity, propName, null, EntityMode.Poco); return; } object relatedEntity = GetPropertyValue(meta, entity, propName); if (relatedEntity != null) return; // entities are already connected relatedEntity = GetRelatedEntity(propName, propType, entityInfo, meta); if (relatedEntity != null) meta.SetPropertyValue(entity, propName, relatedEntity, EntityMode.Poco); }
/// <summary> /// Get a related entity based on the value of the foreign key. Attempts to find the related entity in the /// saveMap; if its not found there, it is loaded via the Session (which should create a proxy, not actually load /// the entity from the database). /// Related entities are Promoted in the saveOrder according to their state. /// </summary> /// <param name="propName">Name of the navigation/association property of the entity, e.g. "Customer". May be null if the property is the entity's identifier.</param> /// <param name="propType">Type of the property</param> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> /// <returns></returns> private object GetRelatedEntity(string propName, EntityType propType, EntityInfo entityInfo, IClassMetadata meta) { object relatedEntity = null; string foreignKeyName = FindForeignKey(propName, meta); object id = GetForeignKeyValue(entityInfo, meta, foreignKeyName); if (id != null) { EntityInfo relatedEntityInfo = FindInSaveMap(propType.ReturnedClass, id); if (relatedEntityInfo == null) { var state = entityInfo.EntityState; if (state != EntityState.Deleted || !propType.IsNullable) { var relatedEntityName = propType.Name; relatedEntity = session.Load(relatedEntityName, id, LockMode.None); } } else { bool removeReverseRelationship = propType.UseLHSPrimaryKey; AddToGraph(entityInfo, relatedEntityInfo, removeReverseRelationship); relatedEntity = relatedEntityInfo.Entity; } } return relatedEntity; }
/// <summary> /// Get the value of the foreign key property. This comes from the entity, but if that value is /// null, and the entity is deleted, we try to get it from the originalValuesMap. /// </summary> /// <param name="entityInfo">Breeze EntityInfo</param> /// <param name="meta">Metadata for the entity class</param> /// <param name="foreignKeyName">Name of the foreign key property of the entity, e.g. "CustomerID"</param> /// <returns></returns> private object GetForeignKeyValue(EntityInfo entityInfo, IClassMetadata meta, string foreignKeyName) { var entity = entityInfo.Entity; object id = null; if (foreignKeyName == meta.IdentifierPropertyName) id = meta.GetIdentifier(entity, EntityMode.Poco); else if (meta.PropertyNames.Contains(foreignKeyName)) id = meta.GetPropertyValue(entity, foreignKeyName, EntityMode.Poco); else if (meta.IdentifierType.IsComponentType) { // compound key var compType = meta.IdentifierType as ComponentType; var index = Array.IndexOf<string>(compType.PropertyNames, foreignKeyName); if (index >= 0) { var idComp = meta.GetIdentifier(entity, EntityMode.Poco); id = compType.GetPropertyValue(idComp, index, EntityMode.Poco); } } if (id == null && entityInfo.EntityState == EntityState.Deleted) { entityInfo.OriginalValuesMap.TryGetValue(foreignKeyName, out id); } return id; }
protected override bool BeforeSaveEntity(EntityInfo entityInfo) { return true; }
/// <summary> /// True if can save this entity else throw exception /// </summary> /// <exception cref="System.InvalidOperationException"></exception> private bool EntitySaveGuard(EntityInfo arg) { var typeName = arg.Entity.GetType().Name; string saveError; var saveable = arg.Entity as ISaveable; if (saveable == null) { saveError = "changes to '" + typeName + "' are forbidden."; } else switch (arg.EntityState) { case EntityState.Added: saveError = saveable.canAdd(); break; case EntityState.Modified: saveError = saveable.canUpdate(); break; case EntityState.Deleted: saveError = saveable.canDelete(); break; default: var stateName = System.Enum.GetName(typeof(EntityState), arg.EntityState); saveError = " unexpected EntityState of " + stateName; break; } if (saveError == null) return true; throw new System.InvalidOperationException( "'" + arg.Entity.GetType().Name + "' may not be saved because " + saveError); }