private void SetValueWithEvents <T>(T property, object newValue, Action <T, Object, Object> action) where T : StructuralProperty { var oldValue = GetValue(property); if (Object.Equals(oldValue, newValue)) { return; } if (!EntityAspect.OnEntityChanging(EntityAction.PropertyChange)) { return; } action(property, newValue, oldValue); EntityAspect.OnPropertyChanged(this.ParentEntityProperty); if (this.IsAttached) { if (!EntityManager.IsLoadingEntity) { if (this.EntityState == EntityState.Unchanged) { EntityAspect.SetModified(); } } if ((EntityManager.ValidationOptions.ValidationApplicability & ValidationApplicability.OnPropertyChange) > 0) { ValidateProperty(property, newValue); } } }
public override void Clear() { var oldErrors = this.ToList(); base.Clear(); oldErrors.ForEach(ve => EntityAspect.OnErrorsChanged(ve)); }
private void SetValueWithEvents <T>(T property, object newValue, Action <T, Object, Object> action) where T : StructuralProperty { var oldValue = GetValue(property); if (Object.Equals(oldValue, newValue)) { return; } if (!EntityAspect.OnEntityChanging(EntityAction.PropertyChange)) { return; } action(property, newValue, oldValue); EntityAspect.OnPropertyChanged(this.ParentEntityProperty); if (this.IsAttached) { if (!EntityManager.IsLoadingEntity) { if (this.EntityState == EntityState.Unchanged) { EntityAspect.SetModified(); } } // TODO: implement this. //if (entityManager.validationOptions.validateOnPropertyChange) { // entityAspect._validateProperty(newValue, // { entity: entity, property: property, propertyName: propPath, oldValue: oldValue }); //} } }
private void InitializeEntityKey(EntityAspect aspect) { var ek = aspect.EntityKey; // return properties that are = to defaultValues var keyProps = aspect.EntityType.KeyProperties; var keyPropsWithDefaultValues = keyProps .Zip(ek.Values, (kp, kv) => kp.DefaultValue == kv ? kp : null) .Where(kp => kp != null); if (keyPropsWithDefaultValues.Any()) { if (aspect.EntityType.AutoGeneratedKeyType != AutoGeneratedKeyType.None) { GenerateId(aspect.Entity, keyPropsWithDefaultValues.First(p => p.IsAutoIncrementing)); } else { // we will allow attaches of entities where only part of the key is set. if (keyPropsWithDefaultValues.Count() == ek.Values.Length) { throw new Exception("Cannot attach an object of type (" + aspect.EntityType.Name + ") to an EntityManager without first setting its key or setting its entityType 'AutoGeneratedKeyType' property to something other than 'None'"); } } } }
internal void NotifyStateChange(EntityAspect entityAspect, bool needsSave) { entityAspect.OnEntityChanged(EntityAction.EntityStateChange); if (needsSave) { SetHasChanges(true); } else { // called when rejecting a change or merging an unchanged record. // NOTE: this can be slow with lots of entities in the cache. if (this._hasChanges) { if (this.IsLoadingEntity) { this.HasChangesAction = this.HasChangesAction ?? (() => SetHasChanges(null)); } else { SetHasChanges(null); } } } }
/// <summary> /// Triggers the EntityChanged event. /// </summary> /// <param name="entityAspect">The changed entity's EntityAspect.</param> /// <param name="entityAction">The action that caused this change.</param> protected virtual void OnEntityChanged(EntityAspect entityAspect, EntityAction entityAction) { if (EntityChanged != null) { EntityChanged(this, new EntityChangedEventArgs(entityAspect, entityAction)); } }
private void RetainDeletedEntityKeys(IEnumerable <object> syncEntities) { _deletedEntityKeys = syncEntities .Where(e => EntityAspect.Wrap(e).EntityState.IsDeleted()) .Select(e => EntityAspect.Wrap(e).EntityKey) .ToList(); }
SaveResult InsertTestDataBaseLineIntoDb(PersistManager <BloggerContextPg> uut) { var blog = new Blog { Id = -1, Url = "www.example.com" }; var blogEntityAspect = new EntityAspect(blog, EntityState.Added); var post = new Post { BlogId = -1, Content = "I am content", Id = -2, Title = "this is the title", CreatedAt = Instant.FromUtc(2002, 10, 8, 6, 4) }; var postEntityAspect = new EntityAspect(post, EntityState.Added); var saveBundle0 = new ClientSaveBundle(); saveBundle0.AddEntity(blogEntityAspect); saveBundle0.AddEntity(postEntityAspect); var parsedSaveBundle = JObject.Parse(saveBundle0.ToJson()); var saveResult = uut.SaveChanges(parsedSaveBundle.ToString()); return(saveResult); }
internal void NotifyStateChange(EntityAspect entityAspect, bool needsSave) { OnEntityChanged(entityAspect.Entity, EntityAction.EntityStateChange); if (needsSave) { if (!this._hasChanges) { this._hasChanges = true; OnHasChangesChanged(); } } else { // called when rejecting a change or merging an unchanged record. if (this._hasChanges) { // NOTE: this can be slow with lots of entities in the cache. this._hasChanges = this.HasChangesCore(null); if (!this._hasChanges) { OnHasChangesChanged(); } } } }
private EntityAspect AttachEntityAspect(EntityAspect entityAspect, EntityState entityState) { var group = GetEntityGroup(entityAspect.EntityType.ClrType); group.AttachEntityAspect(entityAspect, entityState); entityAspect.LinkRelatedEntities(); return(entityAspect); }
public override void Add(ValidationError item) { if (!this.Contains(item)) { base.Add(item); EntityAspect.OnErrorsChanged(item); } }
public override void OnSaving(TempHireEntities source, EntitySavingEventArgs args) { // Add necessary aggregate root object to the save list for validation and concurrency check List <EntityAspect> rootEas = args.Entities.OfType <IHasRoot>() .Select(e => EntityAspect.Wrap(e.Root)) .Distinct() .Where(ea => ea != null && !ea.IsChanged && !ea.IsNullOrPendingEntity) .ToList(); rootEas.ForEach(ea => ea.SetModified()); rootEas.ForEach(ea => args.Entities.Add(ea.Entity)); }
public override bool Remove(ValidationError item) { if (base.Remove(item)) { EntityAspect.OnErrorsChanged(item); return(true); } else { return(false); } }
private IEnumerable <String> GetTempNavPropNames(EntityAspect entityAspect) { var npNames = entityAspect.EntityType.NavigationProperties.Where(np => { if (!np.IsScalar) { return(false); } var val = (IEntity)entityAspect.GetRawValue(np.Name); return(val != null && val.EntityAspect.HasTemporaryKey); }).Select(np => np.Name); return(npNames); }
private JNode ExportEntityAspectInfo(EntityAspect entityAspect) { var jn = new JNode(); var es = entityAspect.EntityState; jn.AddEnum("entityState", entityAspect.EntityState); jn.AddArray("tempNavPropNames", GetTempNavPropNames(entityAspect)); if (es.IsModified() || es.IsDeleted()) { jn.AddMap("originalValuesMap", entityAspect._originalValuesMap); } return(jn); }
public void ClientSaveBundle_EntityAspect_ChangeValue_Test() { var originalUrl = "www.oldUrl.com"; var newUrl = "www.newUrl.com"; var blog = new Blog { Url = originalUrl }; var blogEntityAspect = new EntityAspect(blog, EntityState.Added); blogEntityAspect.ChangeValue("Url", newUrl); blog.Url.Should().Be(newUrl); blogEntityAspect.OriginalValuesMap.Should() .Contain(KeyValuePair.Create("Url", originalUrl as object)); }
private void RaiseDataChangedEvent(IEnumerable <object> savedEntities, IEnumerable <EntityKey> deletedEntityKeys) { var entityKeys = savedEntities .Select(e => EntityAspect.Wrap(e).EntityKey) .Concat(deletedEntityKeys) .ToList(); if (!entityKeys.Any()) { return; } OnDataChanged(entityKeys); }
public override bool RemoveKey(string key) { var removedError = this[key]; if (removedError != null) { base.RemoveKey(key); EntityAspect.OnErrorsChanged(removedError); return(true); } else { return(false); } }
internal void CheckStateChange(EntityAspect entityAspect, bool wasUnchanged, bool isUnchanged) { if (wasUnchanged) { if (!isUnchanged) { this.NotifyStateChange(entityAspect, true); } } else { if (isUnchanged) { this.NotifyStateChange(entityAspect, false); } } }
public override bool ShouldImportEntity(object entity) { // Only import if the importing EntityManager holds a copy of the entity or its root aggregate in its cache if (EntityManager.FindEntity(EntityAspect.Wrap(entity).EntityKey) != null) { return(true); } var hasRoot = entity as IHasRoot; if (hasRoot != null) { return(EntityManager.FindEntity(EntityAspect.Wrap(hasRoot.Root).EntityKey) != null); } return(false); }
private JNode BuildEntityAspectNode(EntityAspect entityAspect) { var nc = MetadataStore.Instance.NamingConvention; var jn = new JNode(); var entityType = entityAspect.EntityType; jn.AddPrimitive("entityTypeName", entityType.Name); jn.AddEnum("entityState", entityAspect.EntityState); jn.AddPrimitive("defaultResourceName", entityType.DefaultResourceName); jn.AddJNode("originalValuesMap", BuildOriginalValuesMapNode(entityAspect, nc)); var agkType = entityType.AutoGeneratedKeyType; if (agkType != AutoGeneratedKeyType.None) { var agkNode = new JNode(); agkNode.AddPrimitive("propertyName", entityType.KeyProperties[0].Name); agkNode.AddEnum("autoGeneratedKeyType", agkType); jn.AddJNode("autoGeneratedKey", agkNode); } return jn; }
private void OnSaved(object sender, EntitySavedEventArgs e) { try { if (!e.HasError) { var exportEntities = e.Entities .Where(entity => SyncInterceptor.ShouldExportEntity(entity) && !_deletedEntityKeys .Contains(EntityAspect.Wrap(entity).EntityKey)) .ToList(); PublishEntities(exportEntities); } _deletedEntityKeys = null; } finally { IsSaving = false; } }
public void ClientSaveBundle_EntityAndEntityAspectToJson_Test() { var blog = new Blog { Url = "www.example.com", CreatedAt = Instant.FromUtc(2002, 10, 8, 6, 4) }; var blogEntityAspect = new EntityAspect(blog, EntityState.Added); { var uut = new ClientSaveBundle(pascalCase: false); var entityWithAspectAsJson = uut.EntityAndEntityAspectToJObject(blog, blogEntityAspect).ToString(); entityWithAspectAsJson.Should().Contain("\"url\": \"www.example.com\","); Console.WriteLine(entityWithAspectAsJson); } { var uut = new ClientSaveBundle(pascalCase: true); var entityWithAspectAsJson = uut.EntityAndEntityAspectToJObject(blog, blogEntityAspect).ToString(); entityWithAspectAsJson.Should().Contain("\"Url\": \"www.example.com\","); } }
private JNode BuildEntityAspectNode(EntityAspect entityAspect) { var nc = entityAspect.EntityManager.MetadataStore.NamingConvention; var jn = new JNode(); var entityType = entityAspect.EntityType; jn.AddPrimitive("entityTypeName", entityType.NameOnServer); jn.AddEnum("entityState", entityAspect.EntityState); jn.AddPrimitive("defaultResourceName", entityType.DefaultResourceName); jn.AddJNode("originalValuesMap", BuildOriginalValuesMapNode(entityAspect, nc)); var agkType = entityType.AutoGeneratedKeyType; if (agkType != AutoGeneratedKeyType.None) { var agkNode = new JNode(); agkNode.AddPrimitive("propertyName", entityType.KeyProperties[0].Name); agkNode.AddEnum("autoGeneratedKeyType", agkType); jn.AddJNode("autoGeneratedKey", agkNode); } return(jn); }
protected override bool ValidateSave() { base.ValidateSave(); // Create a sandbox to do the validation in. var em = new EntityManager(EntityManager); em.CacheStateManager.RestoreCacheState(EntityManager.CacheStateManager.GetCacheState()); // Find all entities supporting custom validation var entities = em.FindEntities(EntityState.AllButDetached).OfType <EntityBase>().ToList(); foreach (var e in entities) { var entityAspect = EntityAspect.Wrap(e); if (entityAspect.EntityState.IsDeletedOrDetached()) { continue; } var validationErrors = new VerifierResultCollection(); e.Validate(validationErrors); validationErrors = new VerifierResultCollection(entityAspect.ValidationErrors.Concat(validationErrors.Errors)); validationErrors.Where(vr => !entityAspect.ValidationErrors.Contains(vr)) .ForEach(entityAspect.ValidationErrors.Add); if (validationErrors.HasErrors) { throw new EntityServerException(validationErrors.Select(v => v.Message).ToAggregateString("\n"), null, PersistenceOperation.Save, PersistenceFailure.Validation); } } return(true); }
/// <summary> /// Insures that a temporary pk is set if necessary /// </summary> /// <param name="aspect"></param> internal void UpdatePkIfNeeded(EntityAspect aspect) { if (KeyGenerator == null) { return; } var keyProperties = aspect.EntityType.KeyProperties; foreach (var aProperty in keyProperties) { var val = aspect.GetValue(aProperty.Name); var aUniqueId = new UniqueId(aProperty, val); // determine if a temp pk is needed. if (aProperty.IsAutoIncrementing) { if (!KeyGenerator.IsTempId(aUniqueId)) { // generate an id if it wasn't already generated aUniqueId = GenerateId(aspect.Entity, aProperty); } AddToTempIds(aUniqueId); } else if (aProperty.DefaultValue == val) { // do not call GenerateId unless the developer is explicit or the key is autoincrementing. } else { // this occurs if GenerateId was called before Attach - it won't have been added to tempIds in this case. if (KeyGenerator.IsTempId(aUniqueId)) { AddToTempIds(aUniqueId); } } } }
private void Validate(EntitySavingEventArgs args) { var allValidationErrors = new VerifierResultCollection(); foreach (var entity in args.Entities) { var entityAspect = EntityAspect.Wrap(entity); if (entityAspect.EntityState.IsDeletedOrDetached()) { continue; } var validationErrors = Manager.VerifierEngine.Execute(entity); foreach (var d in _configuration.Delegates ?? new EntityManagerDelegate <T> [0]) { d.Validate(entity, validationErrors); } // Extract only validation errors validationErrors = validationErrors.Errors; validationErrors.Where(vr => !entityAspect.ValidationErrors.Contains(vr)) .ForEach(entityAspect.ValidationErrors.Add); validationErrors.ForEach(allValidationErrors.Add); } if (allValidationErrors.HasErrors) { if (!ValidationErrorNotifiers.Any()) { throw new ValidationException(allValidationErrors.Select(v => v.Message).ToAggregateString("\n")); } ValidationErrorNotifiers.ForEach(s => s.OnValidationError(allValidationErrors)); args.Cancel = true; } }
internal void MarkTempIdAsMapped(EntityAspect aspect, bool isMapped) { var keyProperties = aspect.EntityType.KeyProperties; foreach (var aProperty in keyProperties) { UniqueId aUniqueId = new UniqueId(aProperty, aspect.GetValue(aProperty.Name)); if (isMapped) { TempIds.Remove(aUniqueId); } else { if (KeyGenerator == null) { return; } if (KeyGenerator.IsTempId(aUniqueId)) { TempIds.Add(aUniqueId); } } } }
private void ParseObject(JsonContext jsonContext, EntityAspect targetAspect) { // backingStore will be null if not allowed to overwrite the entity. var backingStore = (targetAspect == null) ? null : targetAspect.BackingStore; var dict = (IDictionary<String, JToken>) jsonContext.JObject; var structuralType = jsonContext.StructuralType; dict.ForEach(kvp => { var key = kvp.Key; var prop = structuralType.GetProperty(key); if (prop != null) { if (prop.IsDataProperty) { if (backingStore != null) { var dp = (DataProperty)prop; if (dp.IsComplexProperty) { var newCo = (IComplexObject) kvp.Value.ToObject(dp.ClrType); var co = (IComplexObject)backingStore[key]; var coBacking = co.ComplexAspect.BackingStore; newCo.ComplexAspect.BackingStore.ForEach(kvp2 => { coBacking[kvp2.Key] = kvp2.Value; }); } else { backingStore[key] = kvp.Value.ToObject(dp.ClrType); } } } else { // prop is a ComplexObject var np = (NavigationProperty)prop; if (kvp.Value.HasValues) { JsonContext newContext; if (np.IsScalar) { var nestedOb = (JObject)kvp.Value; newContext = new JsonContext() { JObject = nestedOb, ObjectType = prop.ClrType, Serializer = jsonContext.Serializer }; var entity = (IEntity)CreateAndPopulate(newContext); if (backingStore != null) backingStore[key] = entity; } else { var nestedArray = (JArray)kvp.Value; var navSet = (INavigationSet) TypeFns.CreateGenericInstance(typeof(NavigationSet<>), prop.ClrType); nestedArray.Cast<JObject>().ForEach(jo => { newContext = new JsonContext() { JObject=jo, ObjectType = prop.ClrType, Serializer = jsonContext.Serializer }; var entity = (IEntity)CreateAndPopulate(newContext); navSet.Add(entity); }); // add to existing nav set if there is one otherwise just set it. object tmp; if (backingStore.TryGetValue(key, out tmp)) { var backingNavSet = (INavigationSet) tmp; navSet.Cast<IEntity>().ForEach(e => backingNavSet.Add(e)); } else { navSet.NavigationProperty = np; navSet.ParentEntity = targetAspect.Entity; backingStore[key] = navSet; } } } else { // do nothing //if (!np.IsScalar) { // return TypeFns.ConstructGenericInstance(typeof(NavigationSet<>), prop.ClrType); //} else { // return null; //} } } } else { if (backingStore != null) backingStore[key] = kvp.Value.ToObject<Object>(); } }); }
private void ParseObject(NodeContext nodeContext, EntityAspect targetAspect) { // backingStore will be null if not allowed to overwrite the entity. var backingStore = (targetAspect == null) ? null : targetAspect.BackingStore; var dict = (IDictionary<String, JToken>) nodeContext.Node; var structuralType = nodeContext.StructuralType; // needs to be the current namingConvention var nc = _mappingContext.EntityManager.MetadataStore.NamingConvention; dict.ForEach(kvp => { var key = nc.ServerPropertyNameToClient(kvp.Key, structuralType); var prop = structuralType.GetProperty(key); if (prop != null) { if (prop.IsDataProperty) { if (backingStore != null) { var dp = (DataProperty)prop; if (dp.IsComplexProperty) { var newCo = (IComplexObject) kvp.Value.ToObject(dp.ClrType); var co = (IComplexObject)backingStore[key]; var coBacking = co.ComplexAspect.BackingStore; newCo.ComplexAspect.BackingStore.ForEach(kvp2 => { coBacking[kvp2.Key] = kvp2.Value; }); } else { var val = kvp.Value; if (val.Type == JTokenType.Null && dp.ClrType != typeof(String) && !TypeFns.IsNullableType(dp.ClrType)) { // this can only happen if the client is nonnullable but the server is nullable. backingStore[key] = dp.DefaultValue; } else if (dp.IsEnumType || (dp.DataType.ClrType == typeof (TimeSpan))) { backingStore[key] = val.ToObject(dp.ClrType, _customSerializer); } else { backingStore[key] = val.ToObject(dp.ClrType); } } } } else { // prop is a ComplexObject var np = (NavigationProperty)prop; if (kvp.Value.HasValues) { NodeContext newContext; if (np.IsScalar) { var nestedOb = (JObject)kvp.Value; newContext = new NodeContext() { Node = nestedOb, ObjectType = prop.ClrType, StructuralProperty = np}; var entity = (IEntity)CreateAndPopulate(newContext); if (backingStore != null) backingStore[key] = entity; } else { var nestedArray = (JArray)kvp.Value; var navSet = (INavigationSet) TypeFns.CreateGenericInstance(typeof(NavigationSet<>), prop.ClrType); nestedArray.Cast<JObject>().ForEach(jo => { newContext = new NodeContext() { Node=jo, ObjectType = prop.ClrType, StructuralProperty = np}; var entity = (IEntity)CreateAndPopulate(newContext); navSet.Add(entity); }); // add to existing nav set if there is one otherwise just set it. object tmp; if (backingStore.TryGetValue(key, out tmp)) { var backingNavSet = (INavigationSet) tmp; navSet.Cast<IEntity>().ForEach(e => backingNavSet.Add(e)); } else { navSet.NavigationProperty = np; navSet.ParentEntity = targetAspect.Entity; backingStore[key] = navSet; } } } else { // do nothing //if (!np.IsScalar) { // return TypeFns.ConstructGenericInstance(typeof(NavigationSet<>), prop.ClrType); //} else { // return null; //} } } } else { if (backingStore != null) backingStore[key] = kvp.Value.ToObject<Object>(); } }); }
IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName) { // parent EntityAspect has all of the errors. return(EntityAspect.GetValidationErrors(this.GetPropertyPath(propertyName))); }
private void ParseObject(NodeContext nodeContext, EntityAspect targetAspect) { // backingStore will be null if not allowed to overwrite the entity. var backingStore = (targetAspect == null) ? null : targetAspect.BackingStore; var dict = (IDictionary <String, JToken>)nodeContext.Node; var structuralType = nodeContext.StructuralType; // needs to be the current namingConvention var nc = _mappingContext.EntityManager.MetadataStore.NamingConvention; dict.ForEach(kvp => { var key = nc.ServerPropertyNameToClient(kvp.Key, structuralType); var prop = structuralType.GetProperty(key); if (prop != null) { if (prop.IsDataProperty) { if (backingStore != null) { var dp = (DataProperty)prop; if (dp.IsComplexProperty) { var newCo = (IComplexObject)kvp.Value.ToObject(dp.ClrType); var co = (IComplexObject)backingStore[key]; var coBacking = co.ComplexAspect.BackingStore; newCo.ComplexAspect.BackingStore.ForEach(kvp2 => { coBacking[kvp2.Key] = kvp2.Value; }); } else { var val = kvp.Value; if (val.Type == JTokenType.Null && dp.ClrType != typeof(String) && !TypeFns.IsNullableType(dp.ClrType)) { // this can only happen if the client is nonnullable but the server is nullable. backingStore[key] = dp.DefaultValue; } else if (dp.IsEnumType || (dp.DataType.ClrType == typeof(TimeSpan))) { backingStore[key] = val.ToObject(dp.ClrType, _customSerializer); } else { backingStore[key] = val.ToObject(dp.ClrType); } } } } else { // prop is a ComplexObject var np = (NavigationProperty)prop; if (kvp.Value.HasValues) { NodeContext newContext; if (np.IsScalar) { var nestedOb = (JObject)kvp.Value; newContext = new NodeContext() { Node = nestedOb, ObjectType = prop.ClrType, StructuralProperty = np }; var entity = (IEntity)CreateAndPopulate(newContext); if (backingStore != null) { backingStore[key] = entity; } } else { var nestedArray = (JArray)kvp.Value; var navSet = (INavigationSet)TypeFns.CreateGenericInstance(typeof(NavigationSet <>), prop.ClrType); nestedArray.Cast <JObject>().ForEach(jo => { newContext = new NodeContext() { Node = jo, ObjectType = prop.ClrType, StructuralProperty = np }; var entity = (IEntity)CreateAndPopulate(newContext); navSet.Add(entity); }); // add to existing nav set if there is one otherwise just set it. object tmp; if (backingStore.TryGetValue(key, out tmp)) { var backingNavSet = (INavigationSet)tmp; navSet.Cast <IEntity>().ForEach(e => backingNavSet.Add(e)); } else { navSet.NavigationProperty = np; navSet.ParentEntity = targetAspect.Entity; backingStore[key] = navSet; } } } else { // do nothing //if (!np.IsScalar) { // return TypeFns.ConstructGenericInstance(typeof(NavigationSet<>), prop.ClrType); //} else { // return null; //} } } } else { if (backingStore != null) { backingStore[key] = kvp.Value.ToObject <Object>(); } } }); }
public ValidationErrorCollection(EntityAspect entityAspect) { EntityAspect = entityAspect; }
public EntityFacts(object entity) { _entityAspect = EntityAspect.Wrap(entity); }