blob: 762b56f215e2398b1997aed97d69b7414a21e9be [file] [log] [blame]
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
namespace DataJS.Tests
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Services;
using System.Data.Services.Common;
using System.Globalization;
using System.Linq;
using System.Reflection;
/// <summary>
/// Provides a reflection-based, updatable data context.
/// </summary>
public abstract class ReflectionDataContext
{
// Fields
private List<object> deletedObjects = new List<object>();
private List<Action> pendingChanges;
private static Dictionary<Type, Dictionary<string, IList>> resourceSetsByContextTypeStorage = new Dictionary<Type, Dictionary<string, IList>>();
// Methods
protected ReflectionDataContext()
{
this.MetadataHelper = new ReflectionMetadataHelper(this);
this.pendingChanges = new List<Action>();
if (!resourceSetsByContextTypeStorage.ContainsKey(base.GetType()))
{
resourceSetsByContextTypeStorage.Add(base.GetType(), new Dictionary<string, IList>());
foreach (string resourceSetName in this.MetadataHelper.GetResourceSetNames())
{
Type resourceType = this.MetadataHelper.GetResourceTypeOfSet(resourceSetName);
IList listOfTInstance = Activator.CreateInstance(typeof(List<>).MakeGenericType(new Type[] { resourceType })) as IList;
this.ResourceSetsStorage.Add(resourceSetName, listOfTInstance);
}
}
this.EnsureDataIsInitialized();
}
public virtual void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
{
ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
ExceptionUtilities.CheckArgumentNotNull(resourceToBeAdded, "resourceToBeAdded");
UpdatableToken targetToken = UpdatableToken.AssertIsToken(targetResource, "targetResource");
targetResource = targetToken.Resource;
resourceToBeAdded = UpdatableToken.AssertIsTokenAndResolve(resourceToBeAdded, "resourceToBeAdded");
IList list = this.GetValue(targetToken, propertyName) as IList;
ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", new object[] { propertyName, targetResource.GetType().Name });
this.pendingChanges.Add(delegate {
list.Add(resourceToBeAdded);
});
}
public virtual void ClearChanges()
{
this.pendingChanges.Clear();
}
public void ClearData()
{
this.ResourceSetsStorage.Clear();
}
private static bool CompareETagValues(Dictionary<string, object> resourceCookieValues, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
{
if (concurrencyValues.Count<KeyValuePair<string, object>>() != resourceCookieValues.Count)
{
return false;
}
foreach (KeyValuePair<string, object> keyValuePair in concurrencyValues)
{
if (!resourceCookieValues.ContainsKey(keyValuePair.Key))
{
return false;
}
if (keyValuePair.Value == null)
{
return (resourceCookieValues[keyValuePair.Key] == null);
}
if (!keyValuePair.Value.Equals(resourceCookieValues[keyValuePair.Key]))
{
return false;
}
}
return true;
}
public virtual object CreateResource(string containerName, string fullTypeName)
{
ExceptionUtilities.CheckArgumentNotNull(fullTypeName, "fullTypeName");
UpdatableToken token = this.InstantiateResourceType(fullTypeName);
if (containerName != null)
{
this.pendingChanges.Add(delegate {
this.GetResourceSetEntities(containerName).Add(token.Resource);
});
}
return token;
}
private void DeleteAllReferences(object targetResource)
{
foreach (string currentSetName in this.MetadataHelper.GetResourceSetNames())
{
Type currentEntityType = this.MetadataHelper.GetResourceTypeOfSet(currentSetName);
IList entitySetList = this.GetResourceSetEntities(currentSetName);
foreach (NavigationPropertyInfo navigationProperty in this.MetadataHelper.GetNavigationProperties(GetResourceTypeFullName(currentEntityType)))
{
if (navigationProperty.CollectionElementType != null)
{
foreach (object currentEntityInstance in entitySetList)
{
this.RemoveResourceFromCollectionOnTargetResourceMatch(targetResource, navigationProperty, currentEntityInstance);
}
}
else
{
ExceptionUtilities.CheckObjectNotNull(navigationProperty.PropertyInfo, "Invalid navigation property info", new object[0]);
foreach (object currentEntityInstance in entitySetList)
{
this.SetEntityReferenceToNullOnTargetResourceMatch(targetResource, navigationProperty, currentEntityInstance);
}
}
}
}
}
public virtual void DeleteResource(object targetResource)
{
ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
targetResource = UpdatableToken.AssertIsTokenAndResolve(targetResource, "targetResource");
string resourceSetName = this.GetResourceSetOfTargetResource(targetResource);
ExceptionUtilities.CheckObjectNotNull(resourceSetName, "Unable to find set of the resource to delete", new object[0]);
this.deletedObjects.Add(targetResource);
IList resourceSetList = this.GetResourceSetEntities(resourceSetName);
this.DeleteAllReferences(targetResource);
this.pendingChanges.Add(delegate {
resourceSetList.Remove(targetResource);
});
}
protected abstract void EnsureDataIsInitialized();
protected virtual Type GetCollectionPropertyType(string fullTypeName, string propertyName)
{
Type type = this.MetadataHelper.FindClrTypeByFullName(fullTypeName);
Type collectionType = null;
if (type != null)
{
PropertyInfo property = type.GetProperty(propertyName);
if (property != null)
{
collectionType = property.PropertyType;
}
}
return collectionType;
}
private Dictionary<string, object> GetConcurrencyValues(object targetResource)
{
Dictionary<string, object> etagValues = new Dictionary<string, object>();
foreach (string etagProperty in this.MetadataHelper.GetETagPropertiesOfType(GetResourceTypeFullName(targetResource.GetType())))
{
etagValues.Add(etagProperty, targetResource.GetType().GetProperty(etagProperty).GetValue(targetResource, null));
}
return etagValues;
}
public virtual object GetResource(IQueryable query, string fullTypeName)
{
ExceptionUtilities.CheckArgumentNotNull(query, "query");
object resource = null;
foreach (object r in query)
{
ExceptionUtilities.Assert(resource == null, "Invalid Uri specified. The query '{0}' must refer to a single resource", new object[] { query.ToString() });
resource = r;
}
if (resource == null)
{
return null;
}
if (fullTypeName != null)
{
this.ValidateResourceType(resource, fullTypeName);
}
return new UpdatableToken(resource);
}
public IList<T> GetResourceSetEntities<T>(string resourceSetName)
{
return (IList<T>) this.GetResourceSetEntities(resourceSetName);
}
internal IList GetResourceSetEntities(string resourceSetName)
{
IList entities;
if (!this.ResourceSetsStorage.TryGetValue(resourceSetName, out entities))
{
Type elementType = this.MetadataHelper.GetResourceTypeOfSet(resourceSetName);
entities = (IList) Activator.CreateInstance(typeof(List<>).MakeGenericType(new Type[] { elementType }));
this.ResourceSetsStorage[resourceSetName] = entities;
}
return entities;
}
private string GetResourceSetOfTargetResource(object targetResource)
{
foreach (string currentResourceSetName in this.MetadataHelper.GetResourceSetNames())
{
if (this.GetResourceSetEntities(currentResourceSetName).Contains(targetResource))
{
return currentResourceSetName;
}
}
return null;
}
public static string GetResourceTypeFullName(Type type)
{
return type.FullName.Replace('+', '_');
}
public virtual object GetValue(object targetResource, string propertyName)
{
ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource");
if (token.PendingPropertyUpdates.ContainsKey(propertyName))
{
return token.PendingPropertyUpdates[propertyName];
}
targetResource = token.Resource;
PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
ExceptionUtilities.CheckObjectNotNull(pi, "Cannot find the property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name });
object value = pi.GetValue(targetResource, null);
if ((value != null) && (pi.PropertyType.Assembly == base.GetType().Assembly))
{
ExceptionUtilities.Assert(!this.MetadataHelper.IsTypeAnEntityType(pi.PropertyType), "GetValue should never be called for reference properties. Type was '{0}', property was '{1}'", new object[] { pi.PropertyType.FullName, propertyName });
value = new UpdatableToken(value);
}
return value;
}
private UpdatableToken InstantiateResourceType(string fullTypeName)
{
Type t = this.MetadataHelper.FindClrTypeByFullName(fullTypeName);
object instance = Activator.CreateInstance(t);
UpdatableToken token = new UpdatableToken(instance);
foreach (PropertyInfo p in t.GetProperties())
{
object generatedValue;
PropertyInfo property = p;
if (this.IsCollectionProperty(property))
{
Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(t), property.Name);
if (collectionType != null)
{
object newCollection = Activator.CreateInstance(collectionType);
token.PendingPropertyUpdates[property.Name] = newCollection;
this.pendingChanges.Add(delegate {
property.SetValue(instance, newCollection, null);
});
}
}
if (this.TryGetStoreGeneratedValue(fullTypeName, property.Name, out generatedValue))
{
token.PendingPropertyUpdates[property.Name] = generatedValue;
this.pendingChanges.Add(delegate {
property.SetValue(instance, generatedValue, null);
});
}
}
return token;
}
protected virtual bool IsCollectionProperty(PropertyInfo propertyInfo)
{
return ((typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType) && (propertyInfo.PropertyType != typeof(string))) && (propertyInfo.PropertyType != typeof(byte[])));
}
public virtual void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
{
ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
ExceptionUtilities.CheckArgumentNotNull(resourceToBeRemoved, "resourceToBeRemoved");
UpdatableToken.AssertIsToken(targetResource, "targetResource");
resourceToBeRemoved = UpdatableToken.AssertIsTokenAndResolve(resourceToBeRemoved, "resourceToBeRemoved");
IList list = this.GetValue(targetResource, propertyName) as IList;
ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", new object[] { propertyName, targetResource.GetType().Name });
this.pendingChanges.Add(delegate {
list.Remove(resourceToBeRemoved);
});
}
private void RemoveResourceFromCollectionOnTargetResourceMatch(object targetResource, NavigationPropertyInfo navigationPropertyInfo, object currentEntityInstance)
{
IEnumerable childCollectionObject = navigationPropertyInfo.PropertyInfo.GetValue(currentEntityInstance, null) as IEnumerable;
if (childCollectionObject.Cast<object>().Any<object>(delegate (object o) {
return o == targetResource;
}))
{
MethodInfo removeMethod = navigationPropertyInfo.PropertyInfo.PropertyType.GetMethod("Remove");
this.pendingChanges.Add(delegate {
removeMethod.Invoke(childCollectionObject, new object[] { targetResource });
});
}
}
public virtual object ResetResource(object resource)
{
ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
UpdatableToken token = UpdatableToken.AssertIsToken(resource, "resource");
resource = token.Resource;
token = new UpdatableToken(resource);
object newInstance = Activator.CreateInstance(resource.GetType());
ExceptionUtilities.CheckObjectNotNull(newInstance, "Cannot reset resource because unable to creating new instance of type '{0}' returns null", new object[] { resource.GetType().Name });
foreach (string propertyToReset in this.MetadataHelper.GetPropertiesToReset(GetResourceTypeFullName(resource.GetType())))
{
PropertyInfo pi = newInstance.GetType().GetProperty(propertyToReset);
ExceptionUtilities.CheckObjectNotNull(pi, "Cannot reset resource because unable to find property '{0}'", new object[] { propertyToReset });
object newValue = pi.GetValue(newInstance, null);
this.pendingChanges.Add(delegate {
pi.SetValue(resource, newValue, null);
});
token.PendingPropertyUpdates[propertyToReset] = newValue;
}
return token;
}
public virtual object ResolveResource(object resource)
{
ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
return UpdatableToken.AssertIsTokenAndResolve(resource, "resource");
}
public virtual void SaveChanges()
{
foreach (Action pendingChange in this.pendingChanges)
{
pendingChange();
}
this.pendingChanges.Clear();
foreach (object deleted in this.deletedObjects)
{
foreach (object entity in this.ResourceSetsStorage.SelectMany<KeyValuePair<string, IList>, object>(delegate (KeyValuePair<string, IList> p) {
return p.Value.Cast<object>();
}))
{
ExceptionUtilities.Assert(!object.ReferenceEquals(deleted, entity), "Found deleted entity!", new object[0]);
foreach (PropertyInfo propertyInfo in entity.GetType().GetProperties())
{
object value = propertyInfo.GetValue(entity, null);
ExceptionUtilities.Assert(!object.ReferenceEquals(deleted, value), "Found deleted entity!", new object[0]);
IEnumerable enumerable = value as IEnumerable;
if (enumerable != null)
{
foreach (object valueElement in enumerable.Cast<object>())
{
ExceptionUtilities.Assert(!object.ReferenceEquals(deleted, valueElement), "Found deleted entity!", new object[0]);
}
}
}
}
}
this.deletedObjects.Clear();
}
protected virtual void SetCollectionPropertyValue(object targetResource, PropertyInfo propertyInfo, IEnumerable propertyValue)
{
object collection;
ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
ExceptionUtilities.CheckArgumentNotNull(propertyInfo, "propertyInfo");
ExceptionUtilities.CheckArgumentNotNull(propertyValue, "propertyValue");
Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(propertyInfo.ReflectedType), propertyInfo.Name);
ExceptionUtilities.CheckObjectNotNull(collectionType, "Could not infer collection type for property", new object[0]);
propertyValue = propertyValue.Cast<object>().Select<object, object>(delegate (object o) {
return UpdatableToken.ResolveIfToken(o);
});
ConstructorInfo enumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable) });
if (enumerableConstructor != null)
{
collection = enumerableConstructor.Invoke(new object[] { propertyValue });
}
else if (collectionType.IsGenericType && (collectionType.GetGenericArguments().Count<Type>() == 1))
{
Type typeArgument = collectionType.GetGenericArguments().Single<Type>();
ConstructorInfo typedEnumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable<>).MakeGenericType(new Type[] { typeArgument }) });
if (typedEnumerableConstructor != null)
{
object typedEnumerable = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(new Type[] { typeArgument }).Invoke(null, new object[] { propertyValue });
collection = typedEnumerableConstructor.Invoke(new object[] { typedEnumerable });
}
else
{
MethodInfo typedAddMethod = collectionType.GetMethod("Add", new Type[] { typeArgument });
ExceptionUtilities.CheckObjectNotNull(typedAddMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]);
collection = Activator.CreateInstance(collectionType);
foreach (object element in propertyValue)
{
typedAddMethod.Invoke(collection, new object[] { element });
}
}
}
else
{
MethodInfo addMethod = collectionType.GetMethod("Add");
ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]);
collection = Activator.CreateInstance(collectionType);
foreach (object element in propertyValue)
{
addMethod.Invoke(collection, new object[] { element });
}
}
propertyInfo.SetValue(targetResource, collection, null);
}
public virtual void SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
{
ExceptionUtilities.CheckArgumentNotNull(resourceCookie, "resourceCookie");
ExceptionUtilities.ThrowDataServiceExceptionIfFalse(checkForEquality.HasValue, 0x1a1, "Missing concurrency token for update operation", new object[0]);
ExceptionUtilities.Assert(checkForEquality.Value, "Should not be called with check for equality parameter equal to false", new object[0]);
ExceptionUtilities.CheckArgumentNotNull(concurrencyValues, "concurrencyValues");
if (concurrencyValues.Any<KeyValuePair<string, object>>())
{
resourceCookie = UpdatableToken.AssertIsTokenAndResolve(resourceCookie, "resourceCookie");
ExceptionUtilities.ThrowDataServiceExceptionIfFalse(CompareETagValues(this.GetConcurrencyValues(resourceCookie), concurrencyValues), 0x19c, "Concurrency tokens do not match", new object[0]);
}
}
private void SetEntityReferenceToNullOnTargetResourceMatch(object targetResource, NavigationPropertyInfo navigationPropertyInfo, object currentEntityInstance)
{
if (navigationPropertyInfo.PropertyInfo.GetValue(currentEntityInstance, null) == targetResource)
{
this.pendingChanges.Add(delegate {
navigationPropertyInfo.PropertyInfo.SetValue(currentEntityInstance, null, null);
});
}
}
public virtual void SetReference(object targetResource, string propertyName, object propertyValue)
{
ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
if (propertyValue != null)
{
UpdatableToken.AssertIsToken(propertyValue, "propertyValue");
}
this.SetValue(targetResource, propertyName, propertyValue);
}
public virtual void SetValue(object targetResource, string propertyName, object propertyValue)
{
ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource");
targetResource = token.Resource;
token.PendingPropertyUpdates[propertyName] = propertyValue;
this.pendingChanges.Add(delegate {
object generatedValue;
Type t = targetResource.GetType();
PropertyInfo pi = t.GetProperty(propertyName);
ExceptionUtilities.CheckObjectNotNull(pi, "Unable to find property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name });
if (this.TryGetStoreGeneratedValue(GetResourceTypeFullName(t), propertyName, out generatedValue))
{
propertyValue = generatedValue;
}
if (this.IsCollectionProperty(pi))
{
ExceptionUtilities.CheckObjectNotNull(propertyValue, "Collection property value was null", new object[0]);
IEnumerable enumerable = propertyValue as IEnumerable;
ExceptionUtilities.CheckObjectNotNull(enumerable, "Collection property value was not an enumerable", new object[0]);
this.SetCollectionPropertyValue(targetResource, pi, enumerable);
}
else
{
propertyValue = UpdatableToken.ResolveIfToken(propertyValue);
pi.SetValue(targetResource, propertyValue, null);
}
});
}
protected virtual bool TryGetStoreGeneratedValue(string fullTypeName, string propertyName, out object propertyValue)
{
propertyValue = null;
return false;
}
private void ValidateResourceType(object targetResource, string fullTypeName)
{
ExceptionUtilities.Assert(this.MetadataHelper.FindClrTypeByFullName(fullTypeName).IsAssignableFrom(targetResource.GetType()), "Invalid uri specified. expected type: '{0}', actual type: '{1}'", new object[] { fullTypeName, targetResource.GetType().FullName });
}
// Properties
internal ReflectionMetadataHelper MetadataHelper { get; set; }
internal Dictionary<string, IList> ResourceSetsStorage
{
get
{
Dictionary<string, IList> resourceSetsLookup = null;
Type currentContextType = base.GetType();
ExceptionUtilities.Assert(resourceSetsByContextTypeStorage.TryGetValue(currentContextType, out resourceSetsLookup), "Cannot find resource sets by the context type '{0}'", new object[] { currentContextType });
return resourceSetsLookup;
}
}
#region Inner types.
internal class ReflectionMetadataHelper
{
// Fields
private ReflectionDataContext reflectionDataContext;
// Methods
public ReflectionMetadataHelper(ReflectionDataContext reflectionDataContext)
{
this.reflectionDataContext = reflectionDataContext;
}
public Type FindClrTypeByFullName(string resourceTypeFullName)
{
Type type = this.reflectionDataContext.GetType().Assembly.GetTypes().Where<Type>(delegate (Type t) {
return (ReflectionDataContext.GetResourceTypeFullName(t) == resourceTypeFullName);
}).FirstOrDefault<Type>();
ExceptionUtilities.CheckObjectNotNull(type, "Unable to find type '{0}'", new object[] { resourceTypeFullName });
return type;
}
public string[] GetETagPropertiesOfType(string fullTypeName)
{
Type type = this.FindClrTypeByFullName(fullTypeName);
List<string> etags = new List<string>();
foreach (ETagAttribute customAttribute in type.GetCustomAttributes(typeof(ETagAttribute), true))
{
etags.AddRange(customAttribute.PropertyNames);
}
return etags.ToArray();
}
public string[] GetKeyProperties(string fullTypeName)
{
Type type = this.FindClrTypeByFullName(fullTypeName);
List<string> keyPropertyList = new List<string>();
foreach (PropertyInfo keyProperty in type.GetProperties().Where(pi => pi.Name.Contains("ID")))
{
keyPropertyList.Add(keyProperty.Name);
}
foreach (DataServiceKeyAttribute customAttribute in type.GetCustomAttributes(typeof(DataServiceKeyAttribute), true))
{
keyPropertyList.AddRange(customAttribute.KeyNames);
}
return keyPropertyList.ToArray();
}
public NavigationPropertyInfo[] GetNavigationProperties(string fullTypeName)
{
Type type = this.FindClrTypeByFullName(fullTypeName);
var navigationProperties = new List<NavigationPropertyInfo>();
var keyProperties = new List<string>(this.GetKeyProperties(fullTypeName));
foreach (PropertyInfo pi in type.GetProperties())
{
if (!keyProperties.Contains(pi.Name))
{
if (this.IsTypeAnEntityType(pi.PropertyType))
{
navigationProperties.Add(new NavigationPropertyInfo(pi, null));
}
if (pi.PropertyType.IsGenericType && ((pi.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) || (pi.PropertyType.GetGenericTypeDefinition() == typeof(Collection<>))))
{
Type elementType = pi.PropertyType.GetGenericArguments()[0];
if (this.IsTypeAnEntityType(elementType))
{
navigationProperties.Add(new NavigationPropertyInfo(pi, elementType));
}
}
}
}
return navigationProperties.ToArray();
}
public string[] GetPropertiesToReset(string fullTypeName)
{
Type type = this.FindClrTypeByFullName(fullTypeName);
var keyProperties = new List<string>(this.GetKeyProperties(fullTypeName));
var navigationProperties = new List<string>(this.GetNavigationProperties(fullTypeName).Select(ni =>ni.PropertyInfo.Name));
return type.GetProperties().Where(
pi => !keyProperties.Contains(pi.Name) && !navigationProperties.Contains(pi.Name)
).Select(pi => pi.Name).ToArray();
}
public string[] GetResourceSetNames()
{
return this.reflectionDataContext.GetType().GetProperties().Where(
pi => pi.PropertyType.IsGenericType && (pi.PropertyType.GetGenericTypeDefinition() == typeof(IQueryable<>))
).Select(pi => pi.Name).ToArray();
}
public Type GetResourceTypeOfSet(string resourceSetName)
{
PropertyInfo resourceSetPropertyInfo = this.reflectionDataContext.GetType().GetProperties().Where(pi => pi.Name == resourceSetName).FirstOrDefault();
ExceptionUtilities.CheckObjectNotNull(resourceSetPropertyInfo, "Error finding type of set '{0}'", new object[] { resourceSetName });
return resourceSetPropertyInfo.PropertyType.GetGenericArguments()[0];
}
public bool IsTypeAnEntityType(Type t)
{
foreach (string setName in this.GetResourceSetNames())
{
if (this.GetResourceTypeOfSet(setName).IsAssignableFrom(t))
{
return true;
}
}
return false;
}
}
internal static class ExceptionUtilities
{
// Methods
public static void Assert(bool condition, string errorMessage, params object[] messageArguments)
{
if (!condition)
{
throw new InvalidOperationException("Assertion failed: " + string.Format(CultureInfo.InvariantCulture, errorMessage, messageArguments));
}
}
public static void CheckArgumentNotNull(object argument, string argumentName)
{
if (argument == null)
{
throw new ArgumentNullException(argumentName);
}
}
public static void CheckCollectionNotEmpty<TElement>(IEnumerable<TElement> argument, string argumentName)
{
CheckArgumentNotNull(argument, argumentName);
if (!argument.Any<TElement>())
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Collection argument '{0}' must have at least one element.", new object[] { argumentName }));
}
}
public static void CheckObjectNotNull(object value, string exceptionMessageFormatText, params object[] messageArguments)
{
Assert(exceptionMessageFormatText != null, "message cannnot be null", new object[0]);
Assert(messageArguments != null, "messageArguments cannnot be null", new object[0]);
if (value == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, exceptionMessageFormatText, messageArguments));
}
}
public static void ThrowDataServiceExceptionIfFalse(bool condition, int statusCode, string errorMessage, params object[] messageArguments)
{
if (!condition)
{
throw new DataServiceException(statusCode, string.Format(CultureInfo.InvariantCulture, errorMessage, messageArguments));
}
}
}
public class UpdatableToken
{
// Methods
public UpdatableToken(object resource)
{
ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
this.Resource = resource;
this.PendingPropertyUpdates = new Dictionary<string, object>();
}
public static UpdatableToken AssertIsToken(object resource, string name)
{
ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
UpdatableToken token = resource as UpdatableToken;
ExceptionUtilities.CheckObjectNotNull(token, "{0} was not a token. Type was: '{1}'", new object[] { name, resource.GetType() });
return token;
}
public static object AssertIsTokenAndResolve(object resource, string name)
{
return AssertIsToken(resource, name).Resource;
}
public static object ResolveIfToken(object resource)
{
UpdatableToken token = resource as UpdatableToken;
if (token != null)
{
resource = token.Resource;
}
return resource;
}
// Properties
public IDictionary<string, object> PendingPropertyUpdates { get; set; }
public object Resource { get; set; }
}
internal class NavigationPropertyInfo
{
// Methods
internal NavigationPropertyInfo(PropertyInfo pi, Type collectionElementType)
{
this.PropertyInfo = pi;
this.CollectionElementType = collectionElementType;
}
// Properties
public Type CollectionElementType { get; set; }
public PropertyInfo PropertyInfo { get; set; }
}
#endregion Inner types.
}
}