From b0cf551c66d5ea7915dc7fc1a6c99612ed34eb37 Mon Sep 17 00:00:00 2001 From: Robert Petz Date: Thu, 2 May 2013 10:30:33 -0700 Subject: [PATCH 1/3] Paul's changes during my fork --- .../Tracker.SqlCompact.Entities/Tracker.edmx | 1426 ++++++++--------- .../Tracker.SqlServer.CodeFirst/Entity.csp | 90 +- .../Tracker.SqlServer.Entities/Tracker.edmx | 1404 ++++++++-------- 3 files changed, 1460 insertions(+), 1460 deletions(-) diff --git a/Source/Samples/net40/Tracker.SqlCompact.Entities/Tracker.edmx b/Source/Samples/net40/Tracker.SqlCompact.Entities/Tracker.edmx index 4a03177..05f93e1 100644 --- a/Source/Samples/net40/Tracker.SqlCompact.Entities/Tracker.edmx +++ b/Source/Samples/net40/Tracker.SqlCompact.Entities/Tracker.edmx @@ -1,714 +1,714 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/net40/Tracker.SqlServer.CodeFirst/Entity.csp b/Source/Samples/net40/Tracker.SqlServer.CodeFirst/Entity.csp index bc67dae..25ec03f 100644 --- a/Source/Samples/net40/Tracker.SqlServer.CodeFirst/Entity.csp +++ b/Source/Samples/net40/Tracker.SqlServer.CodeFirst/Entity.csp @@ -1,46 +1,46 @@ - - - - - - - - .\ - .\Entities - .\Mapping - Singular - Singular - Plural - Plural - - - sysdiagrams$ - - - False - - - ^(sp|tbl|udf|vw)_ - - - False - False - .\Queries - By - GetBy - Key - False - .\Mocks - True - Tracker.SqlServer.CodeFirst - - $(TrackerConnectionString) - SchemaExplorer.SqlSchemaProvider,SchemaExplorer.SqlSchemaProvider - - Tracker.SqlServer.CodeFirst.Mapping - Tracker.SqlServer.CodeFirst.Entities - Tracker.SqlServer.CodeFirst.Queries - Tracker.SqlServer.CodeFirst.Mocks - - + + + + + + + + .\ + .\Entities + .\Mapping + Singular + Singular + Plural + Plural + + + sysdiagrams$ + + + False + + + ^(sp|tbl|udf|vw)_ + + + False + False + .\Queries + By + GetBy + Key + False + .\Mocks + True + Tracker.SqlServer.CodeFirst + + $(TrackerConnectionString) + SchemaExplorer.SqlSchemaProvider,SchemaExplorer.SqlSchemaProvider + + Tracker.SqlServer.CodeFirst.Mapping + Tracker.SqlServer.CodeFirst.Entities + Tracker.SqlServer.CodeFirst.Queries + Tracker.SqlServer.CodeFirst.Mocks + + \ No newline at end of file diff --git a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx index 29b2a35..0fca75c 100644 --- a/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx +++ b/Source/Samples/net40/Tracker.SqlServer.Entities/Tracker.edmx @@ -1,703 +1,703 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 469f9962f2bae68dbadf362c528bde144a8b0988 Mon Sep 17 00:00:00 2001 From: Robert Petz Date: Thu, 2 May 2013 10:44:43 -0700 Subject: [PATCH 2/3] Provides Many-to-Many logging Adds in the ability to see when a many-to-many relationship is changed, and provides several extra pieces of metadata on the properties object to give details on what changed, how it changed, and the new endpoints to look at --- .../Audit/AuditEntryState.cs | 37 ++++--- .../Audit/AuditLogger.cs | 102 ++++++++++++++---- .../Audit/AuditProperty.cs | 14 +++ .../Audit/Extensions.cs | 99 +++++++++++++++++ .../EntityFramework.Extended.csproj | 4 +- 5 files changed, 220 insertions(+), 36 deletions(-) create mode 100644 Source/EntityFramework.Extended/Audit/Extensions.cs diff --git a/Source/EntityFramework.Extended/Audit/AuditEntryState.cs b/Source/EntityFramework.Extended/Audit/AuditEntryState.cs index ccbc035..6950e13 100644 --- a/Source/EntityFramework.Extended/Audit/AuditEntryState.cs +++ b/Source/EntityFramework.Extended/Audit/AuditEntryState.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.Data; using System.Data.Metadata.Edm; using System.Data.Objects; +using EntityFramework.Extensions; using EntityFramework.Reflection; namespace EntityFramework.Audit @@ -10,31 +12,34 @@ internal class AuditEntryState { public AuditEntryState(ObjectStateEntry objectStateEntry) { - if (objectStateEntry == null) - throw new ArgumentNullException("objectStateEntry"); + if (objectStateEntry == null) + throw new ArgumentNullException("objectStateEntry"); - if (objectStateEntry.Entity == null) - throw new ArgumentException("The Entity property is null for the specified ObjectStateEntry.", "objectStateEntry"); + if (objectStateEntry.Entity == null) + throw new ArgumentException("The Entity property is null for the specified ObjectStateEntry.", "objectStateEntry"); - ObjectStateEntry = objectStateEntry; - Entity = objectStateEntry.Entity; + ObjectStateEntry = objectStateEntry; + Entity = objectStateEntry.Entity; - EntityType = objectStateEntry.EntitySet.ElementType as EntityType; + EntityType = objectStateEntry.EntitySet.ElementType as EntityType; - Type entityType = objectStateEntry.Entity.GetType(); - entityType = ObjectContext.GetObjectType(entityType); + Type entityType = objectStateEntry.Entity.GetType(); + entityType = ObjectContext.GetObjectType(entityType); - ObjectType = entityType; - EntityAccessor = TypeAccessor.GetAccessor(entityType); + ObjectType = entityType; + EntityAccessor = TypeAccessor.GetAccessor(entityType); - AuditEntity = new AuditEntity(objectStateEntry.Entity) - { - Action = GetAction(objectStateEntry), - }; + AuditEntity = new AuditEntity(objectStateEntry.Entity) + { + Action = GetAction(objectStateEntry), + }; } public ObjectContext ObjectContext { get; set; } public AuditLog AuditLog { get; set; } + public NavigationProperty AdditionalModifiedProperty { get; set; } + public object AdditionalModifiedPropertyEnd { get; set; } + public bool AdditionalModifiedPropertyIsAdd { get; set; } public object Entity { get; private set; } public Type ObjectType { get; private set; } @@ -54,7 +59,7 @@ public bool IsDeleted } public bool IsModified { - get { return AuditEntity.Action == AuditAction.Modified; } + get { return AuditEntity.Action == AuditAction.Modified || AdditionalModifiedProperty != null; } } private static AuditAction GetAction(ObjectStateEntry entity) diff --git a/Source/EntityFramework.Extended/Audit/AuditLogger.cs b/Source/EntityFramework.Extended/Audit/AuditLogger.cs index c0ea0c7..8a72225 100644 --- a/Source/EntityFramework.Extended/Audit/AuditLogger.cs +++ b/Source/EntityFramework.Extended/Audit/AuditLogger.cs @@ -150,16 +150,73 @@ public AuditLog UpdateLog(AuditLog auditLog) // must call to make sure changes are detected ObjectContext.DetectChanges(); - IEnumerable changes = ObjectContext - .ObjectStateManager - .GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified); + IEnumerable changes = ObjectContext + .ObjectStateManager + .GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified) + .Where(t => !t.IsRelationship); + + + foreach (ObjectStateEntry objectStateEntry in ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted).Where(t => t.IsRelationship)) + { + ObjectStateEntry entryLeft = null; + ObjectStateEntry entryRight = null; + var associationEnds = objectStateEntry.GetAssociationEnds(); + NavigationProperty navigationPropertyLeft = objectStateEntry.GetNavigationProperty(associationEnds[0]); + NavigationProperty navigationPropertyRight = objectStateEntry.GetNavigationProperty(associationEnds[1]); + + if (objectStateEntry.State == EntityState.Added) + { + entryLeft = ObjectContext.ObjectStateManager.GetObjectStateEntry((EntityKey)objectStateEntry.CurrentValues[0]); + entryRight = ObjectContext.ObjectStateManager.GetObjectStateEntry((EntityKey)objectStateEntry.CurrentValues[1]); + } + else if (objectStateEntry.State == EntityState.Deleted) + { + entryLeft = ObjectContext.ObjectStateManager.GetObjectStateEntry((EntityKey)objectStateEntry.OriginalValues[0]); + entryRight = ObjectContext.ObjectStateManager.GetObjectStateEntry((EntityKey)objectStateEntry.OriginalValues[1]); + } + + Type entityTypeLeft = entryLeft.Entity.GetType(); + entityTypeLeft = ObjectContext.GetObjectType(entityTypeLeft); + if (Configuration.IsAuditable(entityTypeLeft)) + { + var stateLeft = new AuditEntryState(entryLeft) + { + AuditLog = auditLog, + ObjectContext = ObjectContext, + AdditionalModifiedProperty = navigationPropertyLeft, + AdditionalModifiedPropertyEnd = ObjectContext.GetObjectByKey(entryRight.EntityKey), + AdditionalModifiedPropertyIsAdd = objectStateEntry.State == EntityState.Added + }; + + if (WriteEntity(stateLeft)) + auditLog.Entities.Add(stateLeft.AuditEntity); + } + + Type entityTypeRight = entryRight.Entity.GetType(); + entityTypeRight = ObjectContext.GetObjectType(entityTypeRight); + if (Configuration.IsAuditable(entityTypeRight)) + { + var stateRight = new AuditEntryState(entryRight) + { + AuditLog = auditLog, + ObjectContext = ObjectContext, + AdditionalModifiedProperty = navigationPropertyRight, + AdditionalModifiedPropertyEnd = ObjectContext.GetObjectByKey(entryLeft.EntityKey), + AdditionalModifiedPropertyIsAdd = objectStateEntry.State == EntityState.Added + }; + + if (WriteEntity(stateRight)) + auditLog.Entities.Add(stateRight.AuditEntity); + } + } + + foreach (ObjectStateEntry objectStateEntry in changes) + { + if (objectStateEntry.Entity == null) + continue; + + Type entityType = objectStateEntry.Entity.GetType(); - foreach (ObjectStateEntry objectStateEntry in changes) - { - if (objectStateEntry.Entity == null) - continue; - - Type entityType = objectStateEntry.Entity.GetType(); entityType = ObjectContext.GetObjectType(entityType); if (!Configuration.IsAuditable(entityType)) continue; @@ -308,7 +365,7 @@ private void WriteRelationships(AuditEntryState state) if (!Configuration.IncludeRelationships) return; - var properties = state.EntityType.NavigationProperties; + var properties = state.EntityType.NavigationProperties.ToList(); if (properties.Count == 0) return; @@ -316,7 +373,10 @@ private void WriteRelationships(AuditEntryState state) .GetModifiedProperties() .ToList(); - var type = state.ObjectType; + if (state.AdditionalModifiedProperty != null) + modifiedMembers.Add(state.AdditionalModifiedProperty.Name); + + var type = state.ObjectType; var currentValues = state.IsDeleted ? state.ObjectStateEntry.OriginalValues @@ -328,10 +388,6 @@ private void WriteRelationships(AuditEntryState state) foreach (NavigationProperty navigationProperty in properties) { - if (navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many - || navigationProperty.FromEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many) - continue; - string name = navigationProperty.Name; if (Configuration.IsNotAudited(type, name)) continue; @@ -343,12 +399,16 @@ private void WriteRelationships(AuditEntryState state) bool isModified = IsModifed(navigationProperty, modifiedMembers); + if (navigationProperty == state.AdditionalModifiedProperty) isModified = true; + if (state.IsModified && !isModified && !Configuration.IsAlwaysAudited(type, name)) continue; // this means the property was not changed, skip it - bool isLoaded = IsLoaded(state, navigationProperty, accessor); - if (!isLoaded && !Configuration.LoadRelationships) + bool isLoaded = navigationProperty == state.AdditionalModifiedProperty || + IsLoaded(state, navigationProperty, accessor); + + if (!isLoaded && !Configuration.LoadRelationships) continue; var auditProperty = new AuditProperty(); @@ -362,7 +422,13 @@ private void WriteRelationships(AuditEntryState state) object currentValue; - if (isLoaded) + if (isLoaded && navigationProperty == state.AdditionalModifiedProperty) + { + currentValue = state.AdditionalModifiedPropertyEnd; + auditProperty.IsManyToMany = true; + auditProperty.IsManyToManyAdd = state.AdditionalModifiedPropertyIsAdd; + } + else if (isLoaded) { // get value directly from instance to save db call object valueInstance = accessor.GetValue(state.Entity); diff --git a/Source/EntityFramework.Extended/Audit/AuditProperty.cs b/Source/EntityFramework.Extended/Audit/AuditProperty.cs index bb5d3c7..d30e54f 100644 --- a/Source/EntityFramework.Extended/Audit/AuditProperty.cs +++ b/Source/EntityFramework.Extended/Audit/AuditProperty.cs @@ -56,5 +56,19 @@ public class AuditProperty /// The original value of the property. [XmlElement("original")] public object Original { get; set; } + + /// + /// Gets or sets the is many to many value of the property + /// + /// True if this represents a change to a many to many relationship + [XmlElement("isManyToMany")] + public bool IsManyToMany { get; set; } + + /// + /// Gets or sets the is many to many value of the property + /// + /// True if this many to many change represents an insert, false if a delete + [XmlElement("isManyToManyAdd")] + public bool IsManyToManyAdd { get; set; } } } \ No newline at end of file diff --git a/Source/EntityFramework.Extended/Audit/Extensions.cs b/Source/EntityFramework.Extended/Audit/Extensions.cs new file mode 100644 index 0000000..19dff81 --- /dev/null +++ b/Source/EntityFramework.Extended/Audit/Extensions.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Metadata.Edm; +using System.Data.Objects; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework.Audit +{ + public static class Extensions + { + public static IExtendedDataRecord UsableValues(this ObjectStateEntry entry) + { + switch (entry.State) + { + case EntityState.Added: + case EntityState.Detached: + case EntityState.Unchanged: + case EntityState.Modified: + return (IExtendedDataRecord)entry.CurrentValues; + case EntityState.Deleted: + return (IExtendedDataRecord)entry.OriginalValues; + default: + throw new InvalidOperationException("This entity state should not exist."); + } + } + + public static AssociationEndMember[] GetAssociationEnds(this ObjectStateEntry entry) + { + var fieldMetadata = + entry.UsableValues().DataRecordInfo.FieldMetadata; + + return fieldMetadata.Select( + m => m.FieldType as AssociationEndMember).ToArray(); + } + + public static AssociationEndMember GetOtherAssociationEnd( + this ObjectStateEntry entry, AssociationEndMember end) + { + end.ValidateBelongsTo(entry); + AssociationEndMember[] ends = entry.GetAssociationEnds(); + if (ends[0] == end) + { + return ends[1]; + } + return ends[0]; + } + + public static EntityKey GetEndEntityKey(this ObjectStateEntry entry, AssociationEndMember end) + { + end.ValidateBelongsTo(entry); + + AssociationEndMember[] ends = entry.GetAssociationEnds(); + + if (ends[0] == end) + { + return entry.UsableValues()[0] as EntityKey; + } + + return entry.UsableValues()[1] as EntityKey; + } + + public static NavigationProperty GetNavigationProperty(this ObjectStateEntry entry, AssociationEndMember end) + { + end.ValidateBelongsTo(entry); + + var otherEnd = entry.GetOtherAssociationEnd(end); + var relationshipType = entry.EntitySet.ElementType; + var key = entry.GetEndEntityKey(end); + var entitySet = key.GetEntitySet( + entry.ObjectStateManager.MetadataWorkspace); + var property = entitySet.ElementType.NavigationProperties.Where( + p => p.RelationshipType == relationshipType && + p.FromEndMember == end && p.ToEndMember == otherEnd) + .SingleOrDefault(); + return property; + } + + static void ValidateBelongsTo(this AssociationEndMember end, ObjectStateEntry entry) + { + if (!entry.IsRelationship) + { + throw new ArgumentException("is not a relationship entry", "entry"); + } + + var fieldMetadata = + entry.UsableValues().DataRecordInfo.FieldMetadata; + if (fieldMetadata[0].FieldType as AssociationEndMember != end && + fieldMetadata[1].FieldType as AssociationEndMember != end) + { + throw new InvalidOperationException(string.Format( + "association end {0} does not participate in the " + + "relationship {1}", end, entry)); + } + } + } +} diff --git a/Source/EntityFramework.Extended/EntityFramework.Extended.csproj b/Source/EntityFramework.Extended/EntityFramework.Extended.csproj index 5d35fef..bc5d68f 100644 --- a/Source/EntityFramework.Extended/EntityFramework.Extended.csproj +++ b/Source/EntityFramework.Extended/EntityFramework.Extended.csproj @@ -44,8 +44,7 @@ ..\EntityFramework.Extended.snk - - False + ..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll @@ -73,6 +72,7 @@ + From 32e835150aca65c19740925ab181c52563869360 Mon Sep 17 00:00:00 2001 From: Dzmitry Mikhalap Date: Fri, 26 Jul 2013 02:36:02 +0300 Subject: [PATCH 3/3] fix: work with inherited objects --- .../Audit/AuditEntryState.cs | 4 +-- .../Audit/AuditLogger.cs | 11 ++++-- .../Audit/Extensions.cs | 35 ++++++++++++++----- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Source/EntityFramework.Extended/Audit/AuditEntryState.cs b/Source/EntityFramework.Extended/Audit/AuditEntryState.cs index 6950e13..1c9034a 100644 --- a/Source/EntityFramework.Extended/Audit/AuditEntryState.cs +++ b/Source/EntityFramework.Extended/Audit/AuditEntryState.cs @@ -21,7 +21,7 @@ public AuditEntryState(ObjectStateEntry objectStateEntry) ObjectStateEntry = objectStateEntry; Entity = objectStateEntry.Entity; - EntityType = objectStateEntry.EntitySet.ElementType as EntityType; + EntityType = Extensions.GetInheritedEntityType(objectStateEntry); Type entityType = objectStateEntry.Entity.GetType(); entityType = ObjectContext.GetObjectType(entityType); @@ -59,7 +59,7 @@ public bool IsDeleted } public bool IsModified { - get { return AuditEntity.Action == AuditAction.Modified || AdditionalModifiedProperty != null; } + get { return AuditEntity.Action == AuditAction.Modified; } } private static AuditAction GetAction(ObjectStateEntry entity) diff --git a/Source/EntityFramework.Extended/Audit/AuditLogger.cs b/Source/EntityFramework.Extended/Audit/AuditLogger.cs index 8a72225..14b05f0 100644 --- a/Source/EntityFramework.Extended/Audit/AuditLogger.cs +++ b/Source/EntityFramework.Extended/Audit/AuditLogger.cs @@ -569,7 +569,7 @@ private static object GetDisplayValue(AuditEntryState state, NavigationProperty return null; var edmType = referentialConstraint - .FromProperties + .ToProperties .Select(p => p.DeclaringType) .FirstOrDefault(); @@ -634,13 +634,18 @@ private static bool IsLoaded(AuditEntryState state, NavigationProperty navigatio { var relationshipManager = state.ObjectStateEntry.RelationshipManager; var getEntityReference = _relatedAccessor.Value.MakeGenericMethod(accessor.MemberType); - var parameters = new[] + var parameters = new object[] { navigationProperty.RelationshipType.FullName, navigationProperty.ToEndMember.Name }; - var entityReference = getEntityReference.Invoke(relationshipManager, parameters) as EntityReference; + EntityReference entityReference = null; + try + { + entityReference = getEntityReference.Invoke(relationshipManager, parameters) as EntityReference; + } + catch(TargetInvocationException){} return (entityReference != null && entityReference.IsLoaded); } diff --git a/Source/EntityFramework.Extended/Audit/Extensions.cs b/Source/EntityFramework.Extended/Audit/Extensions.cs index 19dff81..c72b318 100644 --- a/Source/EntityFramework.Extended/Audit/Extensions.cs +++ b/Source/EntityFramework.Extended/Audit/Extensions.cs @@ -3,6 +3,7 @@ using System.Data; using System.Data.Metadata.Edm; using System.Data.Objects; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -68,14 +69,12 @@ public static NavigationProperty GetNavigationProperty(this ObjectStateEntry ent var otherEnd = entry.GetOtherAssociationEnd(end); var relationshipType = entry.EntitySet.ElementType; - var key = entry.GetEndEntityKey(end); - var entitySet = key.GetEntitySet( - entry.ObjectStateManager.MetadataWorkspace); - var property = entitySet.ElementType.NavigationProperties.Where( - p => p.RelationshipType == relationshipType && - p.FromEndMember == end && p.ToEndMember == otherEnd) - .SingleOrDefault(); - return property; + + EntityType elementType = GetInheritedEntityTypeByEntityName(entry, end.Name); + NavigationProperty property = + elementType.NavigationProperties.SingleOrDefault(p => p.RelationshipType == relationshipType && + p.FromEndMember == end && p.ToEndMember == otherEnd); + return property; } static void ValidateBelongsTo(this AssociationEndMember end, ObjectStateEntry entry) @@ -95,5 +94,25 @@ static void ValidateBelongsTo(this AssociationEndMember end, ObjectStateEntry en "relationship {1}", end, entry)); } } + + public static EntityType GetInheritedEntityType(ObjectStateEntry entry) + { + if (entry.Entity == null) + { + throw new ArgumentException("entity is null", "entry"); + } + string entityName = entry.Entity.GetType().Name; + return GetInheritedEntityTypeByEntityName(entry, entityName); + } + + static EntityType GetInheritedEntityTypeByEntityName(ObjectStateEntry entry, string entityName) + { + var stateEntryEdmType = + (EntityType) + entry.ObjectStateManager.MetadataWorkspace.GetType(entityName, entry.EntitySet.ElementType.NamespaceName, + DataSpace.CSpace); + + return stateEntryEdmType; + } } }