//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Xml.Linq;
namespace SchoolSample.EntityModel
{
// Helper class that captures most of the change tracking work that needs to be done
// for self tracking entities.
[DataContract(IsReference = true)]
public class ObjectChangeTracker
{
#region Fields
private object _parentObject;
private bool _isDeserializing;
private ObjectState _objectState = ObjectState.Added;
private bool _changeTrackingEnabled;
private OriginalValuesDictionary _originalValues;
private ComplexTypeOriginalValuesDictionary _complexTypeOriginalValues;
private ExtendedPropertiesDictionary _extendedProperties;
private ObjectsAddedToCollectionProperties _objectsAddedToCollections = new ObjectsAddedToCollectionProperties();
private ObjectsRemovedFromCollectionProperties _objectsRemovedFromCollections = new ObjectsRemovedFromCollectionProperties();
#endregion
#region Events
public event EventHandler<ObjectStateChangingEventArgs> ObjectStateChanging;
public event EventHandler<ObjectStateChangedEventArgs> ObjectStateChanged;
public event EventHandler UpdateHasChanges;
protected virtual void OnObjectStateChanging(ObjectState newState)
{
if (ObjectStateChanging != null)
{
ObjectStateChanging(this, new ObjectStateChangingEventArgs { NewState = newState });
}
}
protected virtual void OnObjectStateChanged(ObjectState newState)
{
if (ObjectStateChanged != null)
{
ObjectStateChanged(this, new ObjectStateChangedEventArgs { NewState = newState });
}
}
protected virtual void OnUpdateHasChanges()
{
if (UpdateHasChanges != null)
{
UpdateHasChanges(this, new EventArgs());
}
}
#endregion
#region Public Properties
[DataMember]
public ObjectState State
{
get { return _objectState; }
set
{
if (_objectState != value)
{
if (_isDeserializing || _changeTrackingEnabled)
{
OnObjectStateChanging(value);
_objectState = value;
OnObjectStateChanged(value);
}
}
}
}
public bool ChangeTrackingEnabled
{
get { return _changeTrackingEnabled; }
set
{
if (_changeTrackingEnabled != value)
{
_changeTrackingEnabled = value;
OnUpdateHasChanges();
}
}
}
// Returns the removed objects to collection valued properties that were changed.
[DataMember]
public ObjectsRemovedFromCollectionProperties ObjectsRemovedFromCollectionProperties
{
get
{
if (_objectsRemovedFromCollections == null)
{
_objectsRemovedFromCollections = new ObjectsRemovedFromCollectionProperties();
}
return _objectsRemovedFromCollections;
}
}
// Returns the original values for properties that were changed.
[DataMember]
public OriginalValuesDictionary OriginalValues
{
get
{
if (_originalValues == null)
{
_originalValues = new OriginalValuesDictionary();
}
return _originalValues;
}
}
// Returns the original values for Complex properties that were changed.
[DataMember]
public ComplexTypeOriginalValuesDictionary ComplexTypeOriginalValues
{
get
{
if (_complexTypeOriginalValues == null)
{
_complexTypeOriginalValues = new ComplexTypeOriginalValuesDictionary();
}
return _complexTypeOriginalValues;
}
}
// Returns the extended property values.
// This includes key values for independent associations that are needed for the
// concurrency model in the Entity Framework
[DataMember]
public ExtendedPropertiesDictionary ExtendedProperties
{
get
{
if (_extendedProperties == null)
{
_extendedProperties = new ExtendedPropertiesDictionary();
}
return _extendedProperties;
}
}
// Returns the added objects to collection valued properties that were changed.
[DataMember]
public ObjectsAddedToCollectionProperties ObjectsAddedToCollectionProperties
{
get
{
if (_objectsAddedToCollections == null)
{
_objectsAddedToCollections = new ObjectsAddedToCollectionProperties();
}
return _objectsAddedToCollections;
}
}
#endregion
#region Methods for Change Tracking on Client
[OnDeserializing]
public void OnDeserializingMethod(StreamingContext context)
{
_isDeserializing = true;
}
[OnDeserialized]
public void OnDeserializedMethod(StreamingContext context)
{
_isDeserializing = false;
}
// Resets the ObjectChangeTracker to the Unchanged state and
// clears the original values as well as the record of changes
// to collection properties
public void AcceptChanges()
{
OnObjectStateChanging(ObjectState.Unchanged);
OriginalValues.Clear();
ComplexTypeOriginalValues.Clear();
ObjectsAddedToCollectionProperties.Clear();
ObjectsRemovedFromCollectionProperties.Clear();
ChangeTrackingEnabled = true;
_objectState = ObjectState.Unchanged;
OnObjectStateChanged(ObjectState.Unchanged);
}
// Resets the ObjectChangeTracker to the Unchanged state and
// rollback the original values as well as the record of changes
// to collection properties
public void RejectChanges()
{
OnObjectStateChanging(ObjectState.Unchanged);
Type type = _parentObject.GetType();
// rollback original values for Primitive Properties
foreach (var originalValue in OriginalValues.ToList())
{
PropertyInfo primitiveProperty = type.GetProperty(originalValue.Key);
if (primitiveProperty != null)
{
primitiveProperty.SetValue(_parentObject, originalValue.Value, null);
}
}
// rollback original values for Complex Properties
foreach (var originalValue in ComplexTypeOriginalValues.ToList())
{
PropertyInfo complexProperty = type.GetProperty(originalValue.Key);
if (complexProperty != null)
{
complexProperty.SetValue(_parentObject, originalValue.Value, null);
}
}
// create copy of ObjectsAddedToCollectionProperties and ObjectsRemovedFromCollectionProperties
Dictionary<string, ObjectList> removeCollection =
ObjectsAddedToCollectionProperties.ToDictionary(n => n.Key, n => n.Value);
Dictionary<string, ObjectList> addCollection =
ObjectsRemovedFromCollectionProperties.ToDictionary(n => n.Key, n => n.Value);
// rollback ObjectsAddedToCollectionProperties
foreach (var entry in removeCollection)
{
PropertyInfo collectionProperty = type.GetProperty(entry.Key);
IList collectionObject = (IList) collectionProperty.GetValue(_parentObject, null);
foreach (object obj in entry.Value.ToList())
collectionObject.Remove(obj);
}
// rollback ObjectsRemovedFromCollectionProperties
foreach (var entry in addCollection)
{
PropertyInfo collectionProperty = type.GetProperty(entry.Key);
IList collectionObject = (IList) collectionProperty.GetValue(_parentObject, null);
foreach (var obj in entry.Value.ToList())
collectionObject.Add(obj);
}
OriginalValues.Clear();
ComplexTypeOriginalValues.Clear();
ObjectsAddedToCollectionProperties.Clear();
ObjectsRemovedFromCollectionProperties.Clear();
_objectState = ObjectState.Unchanged;
OnObjectStateChanged(ObjectState.Unchanged);
}
internal void SetParentObject(object parent)
{
_parentObject = parent;
}
// Clone the ObjectChangeTracker object
internal ObjectChangeTracker Clone()
{
var objectChangeTracker = new ObjectChangeTracker {_objectState = State};
if (OriginalValues != null)
{
objectChangeTracker._originalValues = new OriginalValuesDictionary();
foreach (var originalValue in OriginalValues)
{
(objectChangeTracker._originalValues).Add(originalValue.Key, originalValue.Value);
}
}
if (ComplexTypeOriginalValues != null)
{
objectChangeTracker._complexTypeOriginalValues = new ComplexTypeOriginalValuesDictionary();
foreach (var complexTypeOriginalValue in ComplexTypeOriginalValues)
{
objectChangeTracker._complexTypeOriginalValues.Add(complexTypeOriginalValue.Key,
complexTypeOriginalValue.Value);
}
}
if (ExtendedProperties != null)
{
objectChangeTracker._extendedProperties = new ExtendedPropertiesDictionary();
foreach (var extendedProperty in ExtendedProperties)
{
objectChangeTracker._extendedProperties.Add(extendedProperty.Key, extendedProperty.Value);
}
}
if (ObjectsAddedToCollectionProperties != null)
{
objectChangeTracker._objectsAddedToCollections = new ObjectsAddedToCollectionProperties();
foreach (var objectsAddedToCollectionProperty in ObjectsAddedToCollectionProperties)
{
objectChangeTracker._objectsAddedToCollections.Add(objectsAddedToCollectionProperty.Key,
objectsAddedToCollectionProperty.Value);
}
}
if (ObjectsRemovedFromCollectionProperties != null)
{
objectChangeTracker._objectsRemovedFromCollections = new ObjectsRemovedFromCollectionProperties();
foreach (var objectsRemovedFromCollectionProperty in ObjectsRemovedFromCollectionProperties)
{
objectChangeTracker._objectsRemovedFromCollections.Add(
objectsRemovedFromCollectionProperty.Key, objectsRemovedFromCollectionProperty.Value);
}
}
return objectChangeTracker;
}
// Captures the original value for a property that is changing.
internal void RecordOriginalValue(string propertyName, object value)
{
if (_changeTrackingEnabled && _objectState != ObjectState.Added)
{
if (!OriginalValues.ContainsKey(propertyName))
{
OriginalValues[propertyName] = value;
}
}
}
// Captures the original value for a Complex property that is changing.
internal void RecordComplexTypeOriginalValue(string propertyName, object value)
{
if (_changeTrackingEnabled && _objectState != ObjectState.Added)
{
if (!ComplexTypeOriginalValues.ContainsKey(propertyName))
{
if (!ReferenceEquals(value, null))
{
ComplexTypeOriginalValues[propertyName] = value.Clone();
}
else
{
ComplexTypeOriginalValues[propertyName] = null;
}
}
}
}
// Records an addition to collection valued properties on SelfTracking Entities.
internal void RecordAdditionToCollectionProperties(string propertyName, object value)
{
if (_changeTrackingEnabled)
{
// Add the entity back after deleting it, we should do nothing here then
if (ObjectsRemovedFromCollectionProperties.ContainsKey(propertyName)
&& ObjectsRemovedFromCollectionProperties[propertyName].Contains(value))
{
ObjectsRemovedFromCollectionProperties[propertyName].Remove(value);
if (ObjectsRemovedFromCollectionProperties[propertyName].Count == 0)
{
ObjectsRemovedFromCollectionProperties.Remove(propertyName);
}
OnUpdateHasChanges();
return;
}
if (!ObjectsAddedToCollectionProperties.ContainsKey(propertyName))
{
ObjectsAddedToCollectionProperties[propertyName] = new ObjectList();
ObjectsAddedToCollectionProperties[propertyName].Add(value);
}
else
{
ObjectsAddedToCollectionProperties[propertyName].Add(value);
}
OnUpdateHasChanges();
}
}
// Records a removal to collection valued properties on SelfTracking Entities.
internal void RecordRemovalFromCollectionProperties(string propertyName, object value)
{
if (_changeTrackingEnabled)
{
// Delete the entity back after adding it, we should do nothing here then
if (ObjectsAddedToCollectionProperties.ContainsKey(propertyName)
&& ObjectsAddedToCollectionProperties[propertyName].Contains(value))
{
ObjectsAddedToCollectionProperties[propertyName].Remove(value);
if (ObjectsAddedToCollectionProperties[propertyName].Count == 0)
{
ObjectsAddedToCollectionProperties.Remove(propertyName);
}
OnUpdateHasChanges();
return;
}
if (!ObjectsRemovedFromCollectionProperties.ContainsKey(propertyName))
{
ObjectsRemovedFromCollectionProperties[propertyName] = new ObjectList();
ObjectsRemovedFromCollectionProperties[propertyName].Add(value);
}
else
{
if (!ObjectsRemovedFromCollectionProperties[propertyName].Contains(value))
{
ObjectsRemovedFromCollectionProperties[propertyName].Add(value);
}
}
OnUpdateHasChanges();
}
}
#endregion
}
#region "Enum for Object State"
[Flags]
public enum ObjectState
{
Unchanged = 0x1,
Added = 0x2,
Modified = 0x4,
Deleted = 0x8
}
#endregion
[CollectionDataContract (Name = "ObjectsAddedToCollectionProperties",
ItemName = "AddedObjectsForProperty", KeyName = "CollectionPropertyName", ValueName = "AddedObjects")]
public class ObjectsAddedToCollectionProperties : Dictionary<string, ObjectList> { }
[CollectionDataContract (Name = "ObjectsRemovedFromCollectionProperties",
ItemName = "DeletedObjectsForProperty", KeyName = "CollectionPropertyName",ValueName = "DeletedObjects")]
public class ObjectsRemovedFromCollectionProperties : Dictionary<string, ObjectList> { }
[CollectionDataContract(Name = "OriginalValuesDictionary",
ItemName = "OriginalValues", KeyName = "Name", ValueName = "OriginalValue")]
[KnownType(typeof(StatusEnum))]
public class OriginalValuesDictionary : Dictionary<string, Object> { }
[CollectionDataContract(Name = "ComplexTypeOriginalValuesDictionary",
ItemName = "ComplexTypeOriginalValues", KeyName = "Name", ValueName = "OriginalValue")]
public class ComplexTypeOriginalValuesDictionary : Dictionary<string, Object> { }
[CollectionDataContract(Name = "ExtendedPropertiesDictionary",
ItemName = "ExtendedProperties", KeyName = "Name", ValueName = "ExtendedProperty")]
public class ExtendedPropertiesDictionary : Dictionary<string, Object> { }
[CollectionDataContract(ItemName = "ObjectValue")]
public class ObjectList : List<object> { }
// The interface is implemented by the self tracking entities that EF will generate.
// We will have an Adapter that converts this interface to the interface that the EF expects.
// The Adapter will live on the server side.
public interface IObjectWithChangeTracker
{
// Has all the change tracking information for the subgraph of a given object.
ObjectChangeTracker ChangeTracker { get; }
}
public class ObjectStateChangingEventArgs : EventArgs
{
public ObjectState NewState { get; set; }
}
public class ObjectStateChangedEventArgs : EventArgs
{
public ObjectState NewState { get; set; }
}
public static class ObjectWithChangeTrackerExtensions
{
public static T MarkAsDeleted<T>(this T trackingItem) where T : class, IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Deleted;
return trackingItem;
}
public static T MarkAsAdded<T>(this T trackingItem) where T : class, IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Added;
return trackingItem;
}
public static T MarkAsModified<T>(this T trackingItem) where T : class, IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Modified;
return trackingItem;
}
public static T MarkAsUnchanged<T>(this T trackingItem) where T : class, IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Unchanged;
return trackingItem;
}
public static void StartTracking(this IObjectWithChangeTracker trackingItem)
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
}
public static void StopTracking(this IObjectWithChangeTracker trackingItem)
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = false;
}
public static void AcceptChanges(this IObjectWithChangeTracker trackingItem)
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
var editableObject = trackingItem as IEditableObject;
if (editableObject != null) editableObject.EndEdit();
trackingItem.ChangeTracker.AcceptChanges();
}
public static void RejectChanges(this IObjectWithChangeTracker trackingItem)
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
var editableObject = trackingItem as IEditableObject;
if (editableObject != null) editableObject.EndEdit();
trackingItem.ChangeTracker.RejectChanges();
}
public static T Clone<T>(this T source)
{
Type type = source.GetType();
using (Stream stream = new MemoryStream())
{
var serializer = new DataContractSerializer(type);
serializer.WriteObject(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T) serializer.ReadObject(stream);
}
}
}
// An System.Collections.ObjectModel.ObservableCollection that raises
// individual item removal notifications on clear and prevents adding duplicates.
public class TrackableCollection<T> : ObservableCollection<T>
{
protected override void ClearItems()
{
new List<T>(this).ForEach(t => Remove(t));
}
protected override void InsertItem(int index, T item)
{
if (!this.Contains(item))
{
base.InsertItem(index, item);
}
}
}
// An interface that provides an event that fires when complex properties change.
// Changes can be the replacement of a complex property with a new complex type instance or
// a change to a scalar property within a complex type instance.
public interface INotifyComplexPropertyChanging
{
event EventHandler ComplexPropertyChanging;
}
/// <summary>
/// ClientQuery stores a list of include paths and serialized expression tree.
/// </summary>
[DataContract(IsReference = true)]
public class ClientQuery
{
#region Constructor
public ClientQuery(List<string> includeList, XElement xmlExpression)
{
IncludeList = includeList;
XmlExpression = xmlExpression;
}
#endregion Constructor
#region Public DataMember
[DataMember]
public List<string> IncludeList { get; set; }
[DataMember]
public XElement XmlExpression { get; set; }
#endregion Public DataMember
}
public static class EqualityComparer
{
// Helper method to determine if two byte arrays are the same value even if they are different object references
public static bool BinaryEquals(object binaryValue1, object binaryValue2)
{
if (ReferenceEquals(binaryValue1, binaryValue2))
{
return true;
}
byte[] array1 = binaryValue1 as byte[];
byte[] array2 = binaryValue2 as byte[];
if (array1 != null && array2 != null)
{
if (array1.Length != array2.Length)
{
return false;
}
for (int i = 0; i < array1.Length; i++)
{
if (array1[i] != array2[i])
{
return false;
}
}
return true;
}
return false;
}
}
}