public virtual void Update(Type entityType, object entity, IEnumerable <string> properties) { if (entity == null || properties.IsNullOrEmpty()) { return; } Check.NotNull(entityType); entity = entity.CastTo(entityType); entity = entity.DuplicateWithNonNavigations(this.DbContext); DbSet set = this.DbContext.Set(entityType); DbEntityEntry entry = this.DbContext.FindEntry(entity, false); if (entry.State == EntityState.Detached) { set.Attach(entity); } entry.State = EntityState.Unchanged; var values = entity.ToDictionary(); foreach (string name in properties) { DbPropertyEntry property = entry.Property(name); property.IsModified = true; property.CurrentValue = values[name]; } }
/// <summary> /// Get PropertyEntry of source to work on. /// </summary> /// <exception cref="ArgumentNullException"> /// When propertyLambda is null. /// </exception> /// <exception cref="ArgumentException"> /// When propertyLambda does not select a proeprty /// or when Entry has no relevant property. /// </exception> /// <typeparam name="TProperty">Type of property.</typeparam> /// <param name="propertyLambda">Lambda expression to get property.</param> /// <returns>Entry property helper to be able to work on property.</returns> public IEntryPropertyHelper <TProperty> Property <TProperty>( Expression <Func <T, TProperty> > propertyLambda) { if (propertyLambda == null) { throw new ArgumentNullException("propertyLambda"); } PropertyInfo property = propertyLambda.GetPropertyInfo(); if (property == null) { throw new ArgumentException(string.Format( "Expression '{0}' does not select any property.", propertyLambda.ToString())); } DbPropertyEntry propertyEntry = Entry.Property(property.Name); if (propertyEntry == null) { throw new ArgumentException(string.Format( "Entry does not have property with '{0}' name.", property.Name)); } EntryPropertyHelper <TProperty> helper = new EntryPropertyHelper <TProperty>(propertyEntry); return(helper); }
public LoggableProperty(DbPropertyEntry entry, Object originalValue) { PropertyName = entry.Name; OriginalValue = originalValue; CurrentValue = entry.CurrentValue; IsModified = entry.IsModified && !Equals(OriginalValue, CurrentValue); }
private bool ShouldSavePropertyHistory(DbPropertyEntry propertyEntry, PropertyInfo propertyInfo, ICollection <EdmProperty> complexTypeProperties, bool shouldSaveEntityHistory, bool defaultValue) { var shouldSavePropertyHistoryForInfo = ShouldSavePropertyHistoryForInfo(propertyInfo, shouldSaveEntityHistory); if (shouldSavePropertyHistoryForInfo.HasValue) { return(shouldSavePropertyHistoryForInfo.Value); } var isModified = false; if (propertyEntry is DbComplexPropertyEntry) { var complexProperty = complexTypeProperties.Single(t => t.Name == propertyInfo.Name); isModified = propertyEntry.As <DbComplexPropertyEntry>().HasChanged(complexProperty); } else { isModified = propertyEntry.HasChanged(); } if (isModified) { return(true); } return(defaultValue); }
public static DbEntityValidationResult RemoveEFFalseAlarms(this DbContext context, DbEntityValidationResult result, DbEntityEntry entityEntry) { IDirectUpdateContext directContext = context as IDirectUpdateContext; if (directContext != null) { DirectUpdateMode?mode = directContext.CurrentSaveOperationMode; if (mode.HasValue && mode.Value == DirectUpdateMode.AllowAll) { List <DbValidationError> errorsToIgnore = new List <DbValidationError>(); foreach (DbValidationError error in result.ValidationErrors) { if (entityEntry.State == EntityState.Modified) { DbMemberEntry member = entityEntry.Member(error.PropertyName); DbPropertyEntry property = member as DbPropertyEntry; if (property != null) { if (!property.IsModified) { errorsToIgnore.Add(error); } } } } errorsToIgnore.ForEach(e => result.ValidationErrors.Remove(e)); } } return(result); }
public LoggablePropertyEntry(DbPropertyEntry entry, Object originalValue) { IsModified = entry.IsModified && !Object.Equals(originalValue, entry.CurrentValue); this.currentValue = entry.CurrentValue; this.originalValue = originalValue; this.propertyName = entry.Name; }
/// <summary> /// Creates an audit log entry for a <see cref="DbEntityEntry"/> that has an <see cref="EntityState"/> of <see cref="EntityState.Added"/> or <see cref="EntityState.Modified"/> /// It will create an audit log entry for each property that has changed /// </summary> private static AuditLog CreateAuditLogEntryForAddedOrModified(ObjectContext objectContext, DbEntityEntry dbEntry, string tableName, Person person, DateTime changeDate, AuditLogEventType auditLogEventType, DbPropertyEntry modifiedProperty) { var propertyName = modifiedProperty.Name; if (!string.Equals(propertyName, $"{tableName}ID", StringComparison.InvariantCultureIgnoreCase) && !string.Equals(propertyName, "TenantID", StringComparison.InvariantCultureIgnoreCase)) { var optionalAuditDescriptionString = GetAuditDescriptionStringIfAnyForProperty(objectContext, dbEntry, propertyName, auditLogEventType); var auditLogEntry = CreateAuditLogEntryImpl(dbEntry, tableName, person, changeDate, auditLogEventType, propertyName, modifiedProperty.CurrentValue, modifiedProperty.OriginalValue, optionalAuditDescriptionString); return(auditLogEntry); } return(null); }
public int SaveChanges(string login) { // Get all Added/Deleted/Modified entities (not Unmodified or Detached) foreach (var e in ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Modified || p.Entity.GetType().GetProperty("RowVersion") != null)) { if (e.State == EntityState.Added) { if (e.Entity.GetType().GetProperty("CreateDate") != null) { DbPropertyEntry createDate = e.Property("CreateDate"); DbPropertyEntry createBy = e.Property("CreateBy"); createDate.CurrentValue = DateTime.Now; createBy.CurrentValue = login; } } else if (e.State == EntityState.Modified || (e.State == EntityState.Unchanged && e.Entity.GetType().GetProperty("RowVersion") != null)) { if (e.Entity.GetType().GetProperty("EditDate") != null) { DbPropertyEntry editDate = e.Property("EditDate"); DbPropertyEntry editBy = e.Property("EditBy"); editDate.CurrentValue = DateTime.Now; editBy.CurrentValue = login; } } } // Call the original SaveChanges(), which will save both the changes made and the audit records return(base.SaveChanges()); }
public LoggableProperty(DbPropertyEntry entry, Object newValue) { NewValue = newValue; Property = entry.Name; OldValue = entry.CurrentValue; IsModified = entry.IsModified && !Equals(NewValue, OldValue); }
private static bool PropIsModified(DbPropertyEntry prop, IDbContext ctx) { // INFO: "CurrentValue" cannot be used for entities in the Deleted state. // INFO: "OriginalValues" cannot be used for entities in the Added state. //return !AreEqual(prop.CurrentValue, prop.OriginalValue); return(ctx.AutoDetectChangesEnabled ? prop.IsModified : !AreEqual(prop.CurrentValue, prop.OriginalValue)); }
/// <summary> /// EntryProperty helper to work on property of entry. /// </summary> /// <exception cref="ArgumentNullException"> /// When entryPropertyParam is null. /// </exception> /// <param name="entryPropertyParam">Entry proeprty to work on.</param> public EntryPropertyHelper(DbPropertyEntry entryPropertyParam) { if (entryPropertyParam == null) { throw new ArgumentNullException("entryPropertyParam"); } EntryProperty = entryPropertyParam; }
internal static object GetOriginalValue(this DbPropertyEntry propertyEntry) { if (propertyEntry.EntityEntry.State == EntityState.Added) { return(null); } return(propertyEntry.OriginalValue); }
/// <summary> /// 获取实体历史 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="entity">实体对象</param> /// <returns>实体历史</returns> public IEntityHistory GetEntityHistory <T>(T entity) where T : PlainEntity { DbEntityEntry <T> entry = this._dbContext.ChangeTracker.Entries <T>().FirstOrDefault(x => x.Entity.Id == entity.Id); #region # 验证 if (entry == null) { return(null); } #endregion LoginInfo loginInfo = GetLoginInfo?.Invoke(); ActionType actualActionType; IDictionary <string, object> beforeSnapshot = new Dictionary <string, object>(); IDictionary <string, object> afterSnapshot = new Dictionary <string, object>(); if (entry.State == EntityState.Added) { actualActionType = ActionType.Create; foreach (string propertyName in entry.CurrentValues.PropertyNames) { DbPropertyEntry propertyEntry = entry.Property(propertyName); afterSnapshot[propertyName] = propertyEntry.CurrentValue; } } else if (entry.State == EntityState.Modified) { actualActionType = ActionType.Update; foreach (string propertyName in entry.OriginalValues.PropertyNames) { DbPropertyEntry propertyEntry = entry.Property(propertyName); if (propertyEntry.OriginalValue?.ToString() != propertyEntry.CurrentValue?.ToString()) { beforeSnapshot[propertyName] = propertyEntry.OriginalValue; afterSnapshot[propertyName] = propertyEntry.CurrentValue; } } } else if (entry.State == EntityState.Deleted) { actualActionType = ActionType.Delete; foreach (string propertyName in entry.OriginalValues.PropertyNames) { DbPropertyEntry propertyEntry = entry.Property(propertyName); beforeSnapshot[propertyName] = propertyEntry.OriginalValue; } } else { return(null); } EntityHistory entityHistory = new EntityHistory(actualActionType, typeof(T), entry.Entity.Id, beforeSnapshot, afterSnapshot, loginInfo?.LoginId, loginInfo?.RealName); return(entityHistory); }
internal static object GetNewValue(this DbPropertyEntry propertyEntry) { if (propertyEntry.EntityEntry.State == EntityState.Deleted) { return(propertyEntry.OriginalValue); } return(propertyEntry.CurrentValue); }
/// <summary> Sets the values. </summary> /// /// <exception cref="NotSupportedException"> Thrown when the requested operation is not /// supported. </exception> /// /// <param name="dbEntry"> The database entry. </param> /// <param name="entry"> The entry. </param> /// <param name="entityType"> Type of the entity. </param> private static void SetValues(DbEntityEntry dbEntry, DataModificationEntry entry, Type entityType) { if (entry.IsFullReplaceUpdate) { // The algorithm for a "FullReplaceUpdate" is taken from ObjectContextServiceProvider.ResetResource // in WCF DS, and works as follows: // - Create a new, blank instance of the entity. // - Copy over the key values and set any updated values from the client on the new instance. // - Then apply all the properties of the new instance to the instance to be updated. // This will set any unspecified properties to their default value. object newInstance = Activator.CreateInstance(entityType); SetValues(newInstance, entityType, entry.EntityKey); SetValues(newInstance, entityType, entry.LocalValues); dbEntry.CurrentValues.SetValues(newInstance); } else { foreach (KeyValuePair <string, object> propertyPair in entry.LocalValues) { DbPropertyEntry propertyEntry = dbEntry.Property(propertyPair.Key); object value = propertyPair.Value; if (value == null) { // If the property value is null, we set null in the entry too. propertyEntry.CurrentValue = null; continue; } Type type = typeof(string); if (propertyEntry.EntityEntry != null && propertyEntry.EntityEntry.Entity != null) { type = propertyEntry.EntityEntry.Entity.GetType().GetProperty(propertyPair.Key).PropertyType; } else if (propertyEntry.CurrentValue != null) { type = propertyEntry.CurrentValue.GetType(); } if (propertyEntry is DbComplexPropertyEntry) { var dic = value as IReadOnlyDictionary <string, object>; if (dic == null) { throw new NotSupportedException(string.Format("Unsupported type for property: {0}.", propertyPair.Key)); } value = Activator.CreateInstance(type); SetValues(value, type, dic); } propertyEntry.CurrentValue = ConvertToEfValue(type, value); } } }
/// <summary> /// 获取实体历史列表 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="actionType">动作类型</param> /// <returns>实体历史列表</returns> public ICollection <IEntityHistory> GetEntityHistories <T>(ActionType?actionType = null) where T : PlainEntity { LoginInfo loginInfo = GetLoginInfo?.Invoke(); ICollection <IEntityHistory> entityHistories = new HashSet <IEntityHistory>(); IEnumerable <DbEntityEntry <T> > entries = from entry in this._dbContext.ChangeTracker.Entries <T>() where actionType == null || entry.State == (EntityState)actionType.Value select entry; foreach (DbEntityEntry <T> entry in entries) { ActionType actualActionType; IDictionary <string, object> beforeSnapshot = new Dictionary <string, object>(); IDictionary <string, object> afterSnapshot = new Dictionary <string, object>(); if (entry.State == EntityState.Added) { actualActionType = ActionType.Create; foreach (string propertyName in entry.CurrentValues.PropertyNames) { DbPropertyEntry propertyEntry = entry.Property(propertyName); afterSnapshot[propertyName] = propertyEntry.CurrentValue; } } else if (entry.State == EntityState.Modified) { actualActionType = ActionType.Update; foreach (string propertyName in entry.OriginalValues.PropertyNames) { DbPropertyEntry propertyEntry = entry.Property(propertyName); if (propertyEntry.OriginalValue?.ToString() != propertyEntry.CurrentValue?.ToString()) { beforeSnapshot[propertyName] = propertyEntry.OriginalValue; afterSnapshot[propertyName] = propertyEntry.CurrentValue; } } } else if (entry.State == EntityState.Deleted) { actualActionType = ActionType.Delete; foreach (string propertyName in entry.OriginalValues.PropertyNames) { DbPropertyEntry propertyEntry = entry.Property(propertyName); beforeSnapshot[propertyName] = propertyEntry.OriginalValue; } } else { continue; } EntityHistory entityHistory = new EntityHistory(actualActionType, typeof(T), entry.Entity.Id, beforeSnapshot, afterSnapshot, loginInfo?.LoginId, loginInfo?.RealName); entityHistories.Add(entityHistory); } return(entityHistories); }
public void SetUp() { using (TestingContext context = new TestingContext()) { TestModel model = new TestModel(); context.Set <TestModel>().Add(model); context.Entry(model).State = EntityState.Modified; entry = context.Entry(model).Property(property => property.Text); } }
public LoggablePropertyTests() { using (TestingContext context = new TestingContext()) { TestModel model = new TestModel(); context.Set <TestModel>().Attach(model); context.Entry(model).State = EntityState.Modified; textProperty = context.Entry(model).Property(prop => prop.Title); dateProperty = context.Entry(model).Property(prop => prop.CreationDate); } }
/// <summary> /// gets primary keys /// </summary> /// <param name="entry"></param> /// <returns></returns> private int?GetReleaseID(DbEntityEntry entry) { if (entry.GetDatabaseValues().PropertyNames.Contains("ReleaseID") == false) { return(null); } else { DbPropertyEntry releaseIDProperty = entry.Property("ReleaseID"); return(Convert.ToInt32(releaseIDProperty.OriginalValue)); } }
public LoggablePropertyTests() { using (TestingContext context = new TestingContext()) { Role model = ObjectFactory.CreateRole(); context.Set <Role>().Add(model); context.Entry(model).State = EntityState.Modified; textProperty = context.Entry(model).Property(prop => prop.Title); dateProperty = context.Entry(model).Property(prop => prop.CreationDate); } }
public LoggablePropertyTests() { using (TestingContext context = new TestingContext()) { Role model = ObjectFactory.CreateRole(); context.Set<Role>().Add(model); context.Entry(model).State = EntityState.Modified; textProperty = context.Entry(model).Property(prop => prop.Title); dateProperty = context.Entry(model).Property(prop => prop.CreationDate); } }
protected override void ProcessEntities(IEnumerable <DbEntityEntry <Order> > entitesToProcess) { foreach (DbEntityEntry <Order> orderEntry in entitesToProcess) { DbPropertyEntry statusIdProperty = orderEntry.Property("StatusId"); bool isStatusChanged = orderEntry.State != EntityState.Added && statusIdProperty.IsModified && ((int)statusIdProperty.OriginalValue) != ((int)statusIdProperty.CurrentValue); if (orderEntry.State == EntityState.Added || isStatusChanged) { Order order = orderEntry.Entity; order.OrderStatusesHistory.Add(new OrderStatusesHistory() { StatusId = order.StatusId, StatusAssignDate = DateTime.UtcNow }); } if (isStatusChanged) { Order order = orderEntry.Entity; int oldStatusId = (int)statusIdProperty.OriginalValue; int newStatusId = (int)statusIdProperty.CurrentValue; MailSendingFacade mailSender = new MailSendingFacade(); mailSender.SendOrderStatusChangedMail(order.Id, oldStatusId, newStatusId); if (newStatusId == 4) //Изпълнена { RegisterExpenseTask registerExpenseTask = new RegisterExpenseTask(); registerExpenseTask.Execute(new RegisterExpenseContext() { OrderId = order.Id, UserId = order.UserId, ExpenseAmount = order.TotalPrice }); } } if (orderEntry.State == EntityState.Added) { IEnumerable <ArticleOrderCountModel> articleOrderCounts = orderEntry.Entity.OrderDetails.Select(o => new ArticleOrderCountModel() { ArticleId = o.ItemId, OrderCount = o.Quantity }).ToArray(); UpdateArticlesOrdersCountsTask updateArticlesOrdersCountsTask = new UpdateArticlesOrdersCountsTask(); updateArticlesOrdersCountsTask.Execute(articleOrderCounts); } } }
//[TestMethod] public void TestAttach() { LinkMethod lm = null; using (MyDBExt db = new MyDBExt()) { lm = db.LinkMethods.Include(p => p.user).FirstOrDefault(); } User user = null; using (MyDBExt db = new MyDBExt()) { user = db.Users.FirstOrDefault(u => !u.Code.Equals(lm.user.ID)); } lm.MethodType = "B"; lm.user = user; using (MyDBExt db = new MyDBExt()) { // 附加到新上下文 // 方法一 //db.Entry(lm).State = System.Data.EntityState.Modified; //db.Entry<User>(lm.user).State = System.Data.EntityState.Modified; db.LinkMethods.Add(lm); // lm.user的状态也是Added,如果不把lm.user的状态设置为Unchanged,就会出现主键重复的错误 db.Entry <LinkMethod>(lm).State = System.Data.EntityState.Modified; //db.Entry<User>(lm.user).State = System.Data.EntityState.Unchanged; DbReferenceEntry dre = db.Entry <LinkMethod>(lm).Reference(l => l.user); bool x = dre.IsLoaded; User u = lm.user; x = dre.IsLoaded; DbEntityEntry <LinkMethod> dee = db.Entry <LinkMethod>(lm); DbPropertyEntry dpe = dee.Property(l => l.MethodType); //db.LinkMethods.Attach(lm); //lm.user = user; db.SaveChanges(); } using (MyDBExt db = new MyDBExt()) { IQueryable s = db.Users.Select(u => new { u, xX = db.LinkMethods.Where(l => l.user.ID.Equals(u.ID)).Count() }); // OK //IQueryable s = db.Users.Select(u => new { u, xX = db.LinkMethods.Where(l => l.user.ID.Equals(u.ID)).Select(l => l.MethodType) }); //NO //IQueryable s = db.Users.Select(u => new { u, xX = "ddddddddddddd" }); //OK } }
internal static bool HasChanged(this DbPropertyEntry propertyEntry) { if (propertyEntry.EntityEntry.State == EntityState.Added) { return(propertyEntry.CurrentValue != null); } if (propertyEntry.EntityEntry.State == EntityState.Deleted) { return(propertyEntry.OriginalValue != null); } return(!(propertyEntry.OriginalValue?.Equals(propertyEntry.CurrentValue) ?? propertyEntry.CurrentValue == null)); }
/// <summary> /// update all changed records with current timestamp /// </summary> /// <param name="context"> /// The context. /// </param> public static void UpdateTimeStamps(this DbContext context) { // timestamp all changed DateTime now = DateTime.Now; foreach (DbEntityEntry entry in context.ChangeTracker.Entries()) { if ((entry.State & EntityState.Unchanged) == EntityState.Unchanged) { continue; } DbPropertyEntry property = entry.Property("ModifiedDate"); if (property != null) { property.CurrentValue = now; } } }
private static bool PropIsModified(DbPropertyEntry prop) { // TODO: "CurrentValues cannot be used for entities in the Deleted state." var cur = prop.CurrentValue; // TODO: "OriginalValues cannot be used for entities in the Added state." var orig = prop.OriginalValue; if (cur == null && orig == null) { return(false); } if (orig != null) { return(!orig.Equals(cur)); } return(!cur.Equals(orig)); }
private static void SetValues(DbEntityEntry dbEntry, DataModificationEntry entry, Type entityType) { if (entry.IsFullReplaceUpdate) { // The algorithm for a "FullReplaceUpdate" is taken from ObjectContextServiceProvider.ResetResource // in WCF DS, and works as follows: // - Create a new, blank instance of the entity. // - Copy over the key values and set any updated values from the client on the new instance. // - Then apply all the properties of the new instance to the instance to be updated. // This will set any unspecified properties to their default value. object newInstance = Activator.CreateInstance(entityType); SetValues(newInstance, entityType, entry.EntityKey); SetValues(newInstance, entityType, entry.LocalValues); dbEntry.CurrentValues.SetValues(newInstance); } else { foreach (KeyValuePair <string, object> propertyPair in entry.LocalValues) { DbPropertyEntry propertyEntry = dbEntry.Property(propertyPair.Key); object value = propertyPair.Value; if (propertyEntry is DbComplexPropertyEntry) { var dic = value as IReadOnlyDictionary <string, object>; if (dic == null) { // TODO GitHubIssue#103 : Choose property error message for unknown type throw new NotSupportedException("Unsupported type for property:" + propertyPair.Key); } var type = propertyEntry.CurrentValue.GetType(); value = Activator.CreateInstance(type); SetValues(value, type, dic); } propertyEntry.CurrentValue = ConvertToEfDateTimeIfValueIsEdmDate(value); } } }
// // only the changed field will be validate and update // bool checkModify(ref object row) { if (row == null) { return(false); } bool bResult = false; Type type = THelper.GetBaseType(row); foreach (PropertyInfo pro in type.GetProperties()) { if (PropertyHelper.IsVirtual(pro)) { if (PropertyHelper.HasElement(pro)) { var value = pro.GetValue(row); if (checkModify(ref value)) { // set modify pro.SetValue(row, value); bResult = true; } } } else { if (pro.Name == "id") { continue; } if (pro.GetValue(row) != null) { // set modify DbPropertyEntry proEntry = m_db.Entry(row).Property(pro.Name); proEntry.IsModified = true; bResult = true; } } } return(bResult); }
private static bool PropIsModified(DbPropertyEntry prop, bool detectChangesEnabled, IDictionary <string, object> mergedProps) { var propIsModified = prop.IsModified; if (detectChangesEnabled && !propIsModified) { return(false); // Perf } if (propIsModified && mergedProps != null && mergedProps.ContainsKey(prop.Name)) { // EF "thinks" that prop has changed because merged value differs return(false); } // INFO: "CurrentValue" cannot be used for entities in the Deleted state. // INFO: "OriginalValues" cannot be used for entities in the Added state. return(detectChangesEnabled ? propIsModified : !AreEqual(prop.CurrentValue, prop.OriginalValue)); }
public static DbEntityValidationResult RemoveEFFalseAlarms(this DbContext context, DbEntityValidationResult result, DbEntityEntry entityEntry) { //This function doesn't do anything unless AllowAll is the mode IDirectUpdateContext directContext = context as IDirectUpdateContext; if (directContext != null) { UpdateMode?mode = directContext.CurrentSaveOperationMode; if (mode.HasValue && mode.Value == UpdateMode.Allow) { List <DbValidationError> errorsToIgnore = new List <DbValidationError>(); foreach (DbValidationError error in result.ValidationErrors) { if (entityEntry.State == EntityState.Modified) { DbMemberEntry member = entityEntry.Member(error.PropertyName); DbPropertyEntry property = member as DbPropertyEntry; if (property != null) { if (!property.IsModified) { //Add errors that resulted from not changing all the attributes errorsToIgnore.Add(error); } } } } //Then the errors are ignored errorsToIgnore.ForEach(e => result.ValidationErrors.Remove(e)); } } return(result); }
public static List <EntityChange> ExtractChanges(DbContext context, IEnumerable <EntityChangeSource> sources) { var result = new List <EntityChange>(); foreach (var source in sources) { if (source?.Entity == null) { continue; } DbEntityEntry dbEntityEntry = context.Entry(source.Entity); if (dbEntityEntry.State != EntityState.Modified) { continue; } string prefix = source.Prefix ?? ""; foreach (string propName in dbEntityEntry.CurrentValues.PropertyNames) { DbPropertyEntry dbPropertyEntry = dbEntityEntry.Property(propName); if (dbPropertyEntry.IsModified) { result.Add(new EntityChange { PropertyPath = prefix + propName, OriginalValue = dbPropertyEntry.OriginalValue, ChangedValue = dbPropertyEntry.CurrentValue }); } } } return(result); }
private void TestScalarOriginalValue(DbEntityEntry entityEntry, DbPropertyEntry<Building, string> propertyEntry, Type objectType, DbPropertyValues originalValues, string initialValue) { var initialState = entityEntry.State; if (initialState == EntityState.Added) { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.OriginalValue; }).ValidateMessage ("DbPropertyValues_CannotGetValuesForState", "OriginalValues", "Added"); Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = "").ValidateMessage( "DbPropertyValues_CannotGetValuesForState", "OriginalValues", "Added"); return; } if (initialState == EntityState.Detached) { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.OriginalValue; }).ValidateMessage ("DbPropertyEntry_NotSupportedForDetached", "OriginalValue", propertyEntry.Name, entityEntry.Entity.GetType().Name); Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = "").ValidateMessage( "DbPropertyEntry_NotSupportedForDetached", "OriginalValue", propertyEntry.Name, entityEntry.Entity.GetType().Name); return; } Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal(initialValue, propertyEntry.OriginalValue); // Set to same value; prop should not get marked as modified propertyEntry.OriginalValue = initialValue; Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal(initialState, entityEntry.State); // Set to new value; prop marked as modified propertyEntry.OriginalValue = "New Value"; Assert.Equal("New Value", propertyEntry.OriginalValue); CheckPropertyIsModified(entityEntry, propertyEntry, initialState); // New value reflected in record Assert.Equal("New Value", originalValues[propertyEntry.Name]); // Change record; new value reflected in entry originalValues[propertyEntry.Name] = "Another Value"; Assert.Equal("Another Value", propertyEntry.OriginalValue); // Set to null propertyEntry.OriginalValue = null; Assert.Equal(null, propertyEntry.OriginalValue); }
private void TestScalarCurrentValue(DbEntityEntry entityEntry, DbPropertyEntry<Building, string> propertyEntry, DbPropertyValues currentValues, Func<string> getter, string initialValue) { var initialState = entityEntry.State; Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal(initialValue, propertyEntry.CurrentValue); // Set to same value; prop should not get marked as modified propertyEntry.CurrentValue = initialValue; Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal(initialState, entityEntry.State); // Set to new value; prop marked as modified propertyEntry.CurrentValue = "New Value"; Assert.Equal("New Value", propertyEntry.CurrentValue); Assert.Equal("New Value", getter()); CheckPropertyIsModified(entityEntry, propertyEntry, initialState); // New value reflected in record if (initialState != EntityState.Deleted && initialState != EntityState.Detached) { Assert.Equal("New Value", currentValues[propertyEntry.Name]); // Change record; new value reflected in entry currentValues[propertyEntry.Name] = "Another Value"; Assert.Equal("Another Value", propertyEntry.CurrentValue); Assert.Equal("Another Value", getter()); } // Set to null propertyEntry.CurrentValue = null; Assert.Null(propertyEntry.CurrentValue); Assert.Null(getter()); }
private void TestOriginalValueNotInModel(DbEntityEntry entityEntry, DbPropertyEntry<Building, string> propertyEntry) { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.OriginalValue; }).ValidateMessage( "DbPropertyEntry_NotSupportedForPropertiesNotInTheModel", "OriginalValue", propertyEntry.Name, entityEntry.Entity.GetType().Name); Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = "").ValidateMessage( "DbPropertyEntry_NotSupportedForPropertiesNotInTheModel", "OriginalValue", propertyEntry.Name, entityEntry.Entity.GetType().Name); }
private void TestIsModifiedNotInModel(DbEntityEntry entityEntry, DbPropertyEntry<Building, string> propertyEntry) { Assert.False(propertyEntry.IsModified); Assert.Throws<InvalidOperationException>(() => propertyEntry.IsModified = true).ValidateMessage( "DbPropertyEntry_NotSupportedForPropertiesNotInTheModel", "IsModified", propertyEntry.Name, entityEntry.Entity.GetType().Name); }
private void TestCurrentValueNotInModel(DbEntityEntry entityEntry, DbPropertyEntry propertyEntry, Type objectType, Func<string> getter, string initialValue, bool hasGetter, bool hasSetter) { Assert.False(propertyEntry.IsModified); if (hasGetter) { Assert.Equal(initialValue, propertyEntry.CurrentValue); } else { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.CurrentValue; }).ValidateMessage( "DbPropertyEntry_CannotGetCurrentValue", propertyEntry.Name, objectType.Name); } // Set to new value; prop still not modified because it is not in the model if (hasSetter) { propertyEntry.CurrentValue = "New Value"; if (hasGetter) { Assert.Equal("New Value", propertyEntry.CurrentValue); } Assert.Equal("New Value", getter()); // Set to null propertyEntry.CurrentValue = null; Assert.Null(getter()); } else { Assert.Throws<InvalidOperationException>(() => { propertyEntry.CurrentValue = ""; }).ValidateMessage( "DbPropertyEntry_CannotSetCurrentValue", propertyEntry.Name, objectType.Name); } Assert.False(propertyEntry.IsModified); }
private void TestIsModified(DbEntityEntry entityEntry, DbPropertyEntry propertyEntry) { var initialState = entityEntry.State; if (initialState == EntityState.Detached) { Assert.False(propertyEntry.IsModified); Assert.Throws<InvalidOperationException>(() => propertyEntry.IsModified = true).ValidateMessage( "DbPropertyEntry_NotSupportedForDetached", "IsModified", propertyEntry.Name, entityEntry.Entity.GetType().Name); return; } if (initialState == EntityState.Added || initialState == EntityState.Deleted) { Assert.False(propertyEntry.IsModified); Assert.Throws<InvalidOperationException>(() => propertyEntry.IsModified = true).ValidateMessage( "ObjectStateEntry_SetModifiedStates"); return; } propertyEntry.IsModified = true; Assert.True(propertyEntry.IsModified); }
private void TestComplexOriginalValue(DbEntityEntry<Building> entityEntry, DbPropertyEntry<Building, SiteInfo> propertyEntry) { var initialState = entityEntry.State; if (initialState == EntityState.Added) { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.OriginalValue; }).ValidateMessage ("DbPropertyValues_CannotGetValuesForState", "OriginalValues", "Added"); Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = new SiteInfo()). ValidateMessage("DbPropertyValues_CannotGetValuesForState", "OriginalValues", "Added"); return; } if (initialState == EntityState.Detached) { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.OriginalValue; }).ValidateMessage ("DbPropertyEntry_NotSupportedForDetached", "OriginalValue", propertyEntry.Name, typeof(Building).Name); Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = new SiteInfo()). ValidateMessage("DbPropertyEntry_NotSupportedForDetached", "OriginalValue", propertyEntry.Name, typeof(Building).Name); return; } Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal("Clean", propertyEntry.OriginalValue.Environment); // Set to new object with the same values; should not get marked as modified because no values changing var sameInfo = CloneSiteInfo(propertyEntry.OriginalValue); propertyEntry.OriginalValue = sameInfo; Assert.Equal("Clean", propertyEntry.OriginalValue.Environment); Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal(initialState, entityEntry.State); // Set to new value; prop marked as modified var newInfo = new SiteInfo { Zone = 2, Environment = "Contaminated" }; propertyEntry.OriginalValue = newInfo; Assert.Equal("Contaminated", propertyEntry.OriginalValue.Environment); CheckPropertyIsModified(entityEntry, propertyEntry, initialState); // New value reflected in record if (initialState != EntityState.Added && initialState != EntityState.Detached) { var siteValues = entityEntry.OriginalValues.GetValue<DbPropertyValues>("Address").GetValue<DbPropertyValues>( "SiteInfo"); Assert.Equal("Contaminated", siteValues["Environment"]); // Change record; new value reflected in entry siteValues["Environment"] = "Peachy"; Assert.Equal("Peachy", propertyEntry.OriginalValue.Environment); } // Set to null Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = null).ValidateMessage( "DbPropertyValues_ComplexObjectCannotBeNull", "SiteInfo", "Address"); }
private void TestComplexOriginalValue(DbEntityEntry<Building> entityEntry, DbPropertyEntry<Building, Address> propertyEntry) { var initialState = entityEntry.State; if (initialState == EntityState.Added) { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.OriginalValue; }).ValidateMessage ("DbPropertyValues_CannotGetValuesForState", "OriginalValues", "Added"); Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = new Address()). ValidateMessage("DbPropertyValues_CannotGetValuesForState", "OriginalValues", "Added"); return; } if (initialState == EntityState.Detached) { Assert.Throws<InvalidOperationException>(() => { var _ = propertyEntry.OriginalValue; }).ValidateMessage ("DbPropertyEntry_NotSupportedForDetached", "OriginalValue", propertyEntry.Name, entityEntry.Entity.GetType().Name); Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = new Address()). ValidateMessage("DbPropertyEntry_NotSupportedForDetached", "OriginalValue", propertyEntry.Name, entityEntry.Entity.GetType().Name); return; } Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal("Redmond", propertyEntry.OriginalValue.City); Assert.Equal("Clean", propertyEntry.OriginalValue.SiteInfo.Environment); // Set to new object with the same values; should not get marked as modified because no values changing var sameAddress = CloneAddress(propertyEntry.OriginalValue); propertyEntry.OriginalValue = sameAddress; Assert.Equal("Redmond", propertyEntry.OriginalValue.City); Assert.Equal("Clean", propertyEntry.OriginalValue.SiteInfo.Environment); Assert.Equal(initialState == EntityState.Modified, propertyEntry.IsModified); Assert.Equal(initialState, entityEntry.State); // Set to new value; prop marked as modified var newAddress = new Address { Street = "300 Main St", City = "Ames", State = "IA", ZipCode = "50010", SiteInfo = new SiteInfo { Zone = 2, Environment = "Contaminated" } }; propertyEntry.OriginalValue = newAddress; Assert.Equal("Ames", propertyEntry.OriginalValue.City); Assert.Equal("Contaminated", propertyEntry.OriginalValue.SiteInfo.Environment); CheckPropertyIsModified(entityEntry, propertyEntry, initialState); // New value reflected in record if (initialState != EntityState.Added && initialState != EntityState.Detached) { var addressValues = (DbPropertyValues)entityEntry.OriginalValues["Address"]; var siteValues = (DbPropertyValues)addressValues["SiteInfo"]; Assert.Equal("Ames", addressValues["City"]); Assert.Equal("Contaminated", siteValues["Environment"]); // Change record; new value reflected in entry addressValues["City"] = "Cedar Falls"; siteValues["Environment"] = "Peachy"; Assert.Equal("Cedar Falls", propertyEntry.OriginalValue.City); Assert.Equal("Peachy", propertyEntry.OriginalValue.SiteInfo.Environment); } // Set to null Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = null).ValidateMessage( "DbPropertyValues_ComplexObjectCannotBeNull", "Address", "Building"); // Set to new value that has a nested null complex object // Should always throw, but Originally only throws if the entity is Added/Modified/Unchanged if (initialState != EntityState.Detached && initialState != EntityState.Deleted) { var addressWithNull = new Address { Street = "300 Main St", City = "Ames", State = "IA", ZipCode = "50010", SiteInfo = null }; Assert.Throws<InvalidOperationException>(() => propertyEntry.OriginalValue = addressWithNull). ValidateMessage("DbPropertyValues_ComplexObjectCannotBeNull", "SiteInfo", "Address"); } }
private void CheckPropertyIsModified(DbEntityEntry entityEntry, DbPropertyEntry propertyEntry, EntityState initialState) { if (initialState == EntityState.Modified || initialState == EntityState.Unchanged) { Assert.True(propertyEntry.IsModified); Assert.Equal(EntityState.Modified, entityEntry.State); } else { Assert.False(propertyEntry.IsModified); Assert.Equal(initialState, entityEntry.State); } }