Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Metadata / ObjectLayer / ObjectItemConventionAssemblyLoader.cs / 1305376 / ObjectItemConventionAssemblyLoader.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Reflection;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System.Data.Entity;
using System.Text;
namespace System.Data.Metadata.Edm
{
internal sealed class ObjectItemConventionAssemblyLoader : ObjectItemAssemblyLoader
{
// for root entities, entities with no base type, we will additionally look
// at properties on the clr base hierarchy.
private const BindingFlags RootEntityPropertyReflectionBindingFlags = PropertyReflectionBindingFlags & ~BindingFlags.DeclaredOnly | BindingFlags.FlattenHierarchy;
private new MutableAssemblyCacheEntry CacheEntry { get { return (MutableAssemblyCacheEntry)base.CacheEntry; } }
private List _referenceResolutions = new List();
internal ObjectItemConventionAssemblyLoader(Assembly assembly, ObjectItemLoadingSessionData sessionData)
: base(assembly, new MutableAssemblyCacheEntry(), sessionData)
{
Debug.Assert(Create == sessionData.ObjectItemAssemblyLoaderFactory, "Why is there a different factory creating this class");
SessionData.RegisterForLevel1PostSessionProcessing(this);
}
protected override void LoadTypesFromAssembly()
{
foreach (Type type in SourceAssembly.GetTypes())
{
StructuralType cspaceType;
if (TryGetCSpaceTypeMatch(type, out cspaceType))
{
if (type.IsValueType)
{
SessionData.LoadMessageLogger.LogLoadMessage(Strings.Validator_OSpace_Convention_Struct(cspaceType.FullName, type.FullName), cspaceType);
continue;
}
EdmType ospaceType;
if (TryCreateType(type, (StructuralType)cspaceType, out ospaceType))
{
CacheEntry.TypesInAssembly.Add(ospaceType);
// check for duplcates so we don't cause an ArgumentException,
// Mapping will do the actual error for the duplicate type later
if (!SessionData.CspaceToOspace.ContainsKey((StructuralType)cspaceType))
{
SessionData.CspaceToOspace.Add((StructuralType)cspaceType, (StructuralType)ospaceType);
}
else
{
// at this point there is already a Clr Type that is structurally matched to this CSpace type, we throw exception
StructuralType previousOSpaceType = SessionData.CspaceToOspace[cspaceType];
SessionData.EdmItemErrors.Add(
new EdmItemError(Strings.Validator_OSpace_Convention_AmbiguousClrType(cspaceType.Name, previousOSpaceType.ClrType.FullName, type.FullName), previousOSpaceType));
}
}
}
}
if (SessionData.TypesInLoading.Count == 0)
{
Debug.Assert(CacheEntry.ClosureAssemblies.Count == 0, "How did we get closure assemblies?");
// since we didn't find any types, don't lock into convention based
SessionData.ObjectItemAssemblyLoaderFactory = null;
}
}
protected override void AddToAssembliesLoaded()
{
SessionData.AssembliesLoaded.Add(SourceAssembly, CacheEntry);
}
private bool TryGetCSpaceTypeMatch(Type type, out StructuralType cspaceType)
{
// brute force try and find a matching name
KeyValuePair pair;
if (SessionData.ConventionCSpaceTypeNames.TryGetValue(type.Name, out pair))
{
if (pair.Value == 1)
{
// we found a type match
cspaceType = pair.Key;
return true;
}
else
{
Debug.Assert(pair.Value > 1, "how did we get a negative count of types in the dictionary?");
SessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_OSpace_Convention_MultipleTypesWithSameName(type.Name), pair.Key));
}
}
cspaceType = null;
return false;
}
private bool TryCreateType(Type type, StructuralType cspaceType, out EdmType newOSpaceType)
{
List referenceResolutionListForCurrentType = new List();
newOSpaceType = null;
Debug.Assert(TypesMatchByConvention(type, cspaceType), "The types passed as parameters don't match by convention.");
StructuralType ospaceType;
if (Helper.IsEntityType(cspaceType))
{
ospaceType = new ClrEntityType(type, cspaceType.NamespaceName, cspaceType.Name);
}
else
{
Debug.Assert(Helper.IsComplexType(cspaceType), "Invalid type attribute encountered");
ospaceType = new ClrComplexType(type, cspaceType.NamespaceName, cspaceType.Name);
}
if (cspaceType.BaseType != null)
{
if (TypesMatchByConvention(type.BaseType, cspaceType.BaseType))
{
TrackClosure(type.BaseType);
referenceResolutionListForCurrentType.Add(
() => ospaceType.BaseType = ResolveBaseType((StructuralType)cspaceType.BaseType, type));
}
else
{
string message = Strings.Validator_OSpace_Convention_BaseTypeIncompatible(type.BaseType.FullName, type.FullName, cspaceType.BaseType.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
// Load the properties for this type
if (!TryCreateMembers(type, (StructuralType)cspaceType, ospaceType, referenceResolutionListForCurrentType))
{
return false;
}
// Add this to the known type map so we won't try to load it again
SessionData.TypesInLoading.Add(type.FullName, ospaceType);
// we only add the referenceResolution to the list unless we structrually matched this type
foreach (var referenceResolution in referenceResolutionListForCurrentType)
{
this._referenceResolutions.Add(referenceResolution);
}
newOSpaceType = ospaceType;
return true;
}
internal override void OnLevel1SessionProcessing()
{
CreateRelationships();
foreach (Action resolve in _referenceResolutions)
{
resolve();
}
base.OnLevel1SessionProcessing();
}
private EdmType ResolveBaseType(StructuralType baseCSpaceType, Type type)
{
StructuralType ospaceType;
bool foundValue = SessionData.CspaceToOspace.TryGetValue(baseCSpaceType, out ospaceType);
if (!foundValue)
{
string message =
SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
Strings.Validator_OSpace_Convention_BaseTypeNotLoaded(type, baseCSpaceType),
baseCSpaceType);
SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
}
return ospaceType;
}
private bool TryCreateMembers(Type type, StructuralType cspaceType, StructuralType ospaceType, List referenceResolutionListForCurrentType)
{
BindingFlags flags = cspaceType.BaseType == null ? RootEntityPropertyReflectionBindingFlags : PropertyReflectionBindingFlags;
PropertyInfo[] clrProperties = type.GetProperties(flags);
// required properties scalar properties first
if (!TryFindAndCreateScalarProperties(type, cspaceType, ospaceType, clrProperties))
{
return false;
}
if (!TryFindComplexProperties(type, cspaceType, ospaceType, clrProperties, referenceResolutionListForCurrentType))
{
return false;
}
if (!TryFindNavigationProperties(type, cspaceType, ospaceType, clrProperties, referenceResolutionListForCurrentType))
{
return false;
}
return true;
}
private bool TryFindComplexProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties, List referenceResolutionListForCurrentType)
{
List> typeClosureToTrack =
new List>();
foreach(EdmProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers().Where(m => Helper.IsComplexType(m.TypeUsage.EdmType)))
{
PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => MemberMatchesByConvention(p, cspaceProperty));
if (clrProperty != null)
{
typeClosureToTrack.Add(
new KeyValuePair(
cspaceProperty, clrProperty));
}
else
{
string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(cspaceProperty.Name, type.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
foreach (var typeToTrack in typeClosureToTrack)
{
TrackClosure(typeToTrack.Value.PropertyType);
// prevent the lifting of these closure variables
var ot = ospaceType;
var cp = typeToTrack.Key;
var clrp = typeToTrack.Value;
referenceResolutionListForCurrentType.Add(() => CreateAndAddComplexType(type, ot, cp, clrp));
}
return true;
}
private bool TryFindNavigationProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties, List referenceResolutionListForCurrentType)
{
List> typeClosureToTrack =
new List>();
foreach (NavigationProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers())
{
PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => NonPrimitiveMemberMatchesByConvention(p, cspaceProperty));
if (clrProperty != null)
{
bool needsSetter = cspaceProperty.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many;
if (clrProperty.CanRead && (!needsSetter || clrProperty.CanWrite))
{
typeClosureToTrack.Add(
new KeyValuePair(
cspaceProperty, clrProperty));
}
}
else
{
string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(
cspaceProperty.Name, type.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
foreach (var typeToTrack in typeClosureToTrack)
{
TrackClosure(typeToTrack.Value.PropertyType);
// keep from lifting these closure variables
var ct = cspaceType;
var ot = ospaceType;
var cp = typeToTrack.Key;
var clrp = typeToTrack.Value;
referenceResolutionListForCurrentType.Add(() => CreateAndAddNavigationProperty(ct, ot, cp, clrp));
}
return true;
}
private void TrackClosure(Type type)
{
if (SourceAssembly != type.Assembly &&
!CacheEntry.ClosureAssemblies.Contains(type.Assembly) &&
!(type.IsGenericType &&
(
EntityUtil.IsAnICollection(type) || // EntityCollection<>, List<>, ICollection<>
type.GetGenericTypeDefinition() == typeof(System.Data.Objects.DataClasses.EntityReference<>) ||
type.GetGenericTypeDefinition() == typeof(System.Nullable<>)
)
)
)
{
CacheEntry.ClosureAssemblies.Add(type.Assembly);
}
if (type.IsGenericType)
{
foreach (Type genericArgument in type.GetGenericArguments())
{
TrackClosure(genericArgument);
}
}
}
private void CreateAndAddComplexType(Type type, StructuralType ospaceType, EdmProperty cspaceProperty, PropertyInfo clrProperty)
{
StructuralType propertyType;
if (SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out propertyType))
{
EdmProperty property = new EdmProperty(cspaceProperty.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = false }), clrProperty, type.TypeHandle);
ospaceType.AddMember(property);
}
else
{
string message =
SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
Strings.Validator_OSpace_Convention_MissingOSpaceType(cspaceProperty.TypeUsage.EdmType.FullName),
cspaceProperty.TypeUsage.EdmType);
SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
}
}
private void CreateAndAddNavigationProperty(StructuralType cspaceType, StructuralType ospaceType, NavigationProperty cspaceProperty, PropertyInfo clrProperty)
{
StructuralType ospaceRelationship;
if (SessionData.CspaceToOspace.TryGetValue(cspaceProperty.RelationshipType, out ospaceRelationship))
{
bool foundTarget = false;
EdmType targetType = null;
if (Helper.IsCollectionType(cspaceProperty.TypeUsage.EdmType))
{
StructuralType findType;
foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)((CollectionType)cspaceProperty.TypeUsage.EdmType).TypeUsage.EdmType, out findType);
if (foundTarget)
{
targetType = findType.GetCollectionType();
}
}
else
{
StructuralType findType;
foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out findType);
if (foundTarget)
{
targetType = findType;
}
}
Debug.Assert(foundTarget, "Since the relationship will only be created if it can find the types for both ends, we will never fail to find one of the ends");
NavigationProperty navigationProperty = new NavigationProperty(cspaceProperty.Name, TypeUsage.Create(targetType), clrProperty);
navigationProperty.RelationshipType = (RelationshipType)ospaceRelationship;
// we can use First because o-space relationships are created directly from
// c-space relationship
navigationProperty.ToEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.ToEndMember.Name);
navigationProperty.FromEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.FromEndMember.Name);
ospaceType.AddMember(navigationProperty);
}
else
{
EntityTypeBase missingType = cspaceProperty.RelationshipType.RelationshipEndMembers.Select(e => ((RefType)e.TypeUsage.EdmType).ElementType).First(e => e != cspaceType);
string message =
SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
Strings.Validator_OSpace_Convention_RelationshipNotLoaded(cspaceProperty.RelationshipType.FullName, missingType.FullName),
missingType);
SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
}
}
private bool TryFindAndCreateScalarProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties)
{
foreach (EdmProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers().Where(p => Helper.IsPrimitiveType(p.TypeUsage.EdmType)))
{
PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => MemberMatchesByConvention(p, cspaceProperty));
if (clrProperty != null)
{
PrimitiveType propertyType;
bool typeIsNullable;
if (TryGetPrimitiveType(clrProperty.PropertyType, out typeIsNullable, out propertyType))
{
if (clrProperty.CanRead && clrProperty.CanWrite)
{
bool isKeyMember = Helper.IsEntityType(cspaceType) && ((EntityType)cspaceType).KeyMemberNames.Contains(clrProperty.Name);
EdmProperty ospaceProperty = new EdmProperty(cspaceProperty.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = typeIsNullable && !isKeyMember }), clrProperty, type.TypeHandle);
if (isKeyMember)
{
((EntityType)ospaceType).AddKeyMember(ospaceProperty);
}
else
{
ospaceType.AddMember(ospaceProperty);
}
}
else
{
string message = Strings.Validator_OSpace_Convention_ScalarPropertyMissginGetterOrSetter(clrProperty.Name, type.FullName, type.Assembly.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
else
{
string message = Strings.Validator_OSpace_Convention_NonPrimitiveTypeProperty(clrProperty.Name, type.FullName, clrProperty.PropertyType.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
else
{
string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(cspaceProperty.Name, type.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
return true;
}
private void CreateRelationships()
{
if (SessionData.ConventionBasedRelationshipsAreLoaded)
{
return;
}
SessionData.ConventionBasedRelationshipsAreLoaded = true;
// find all the relationships
foreach (AssociationType cspaceAssociation in SessionData.EdmItemCollection.GetItems())
{
Debug.Assert(cspaceAssociation.RelationshipEndMembers.Count == 2, "Relationships are assumed to have exactly two ends");
if (SessionData.CspaceToOspace.ContainsKey(cspaceAssociation))
{
// don't try to load relationships that we already know about
continue;
}
StructuralType [] ospaceEndTypes = new StructuralType [2];
if (SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[0]), out ospaceEndTypes[0]) &&
SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[1]), out ospaceEndTypes[1]))
{
// if we can find both ends of the relationship, then create it
AssociationType ospaceAssociation = new AssociationType(cspaceAssociation.Name, cspaceAssociation.NamespaceName, cspaceAssociation.IsForeignKey, DataSpace.OSpace);
for (int i = 0; i < cspaceAssociation.RelationshipEndMembers.Count; i++)
{
EntityType ospaceEndType = (EntityType)ospaceEndTypes[i];
RelationshipEndMember cspaceEnd = cspaceAssociation.RelationshipEndMembers[i];
ospaceAssociation.AddKeyMember(new AssociationEndMember(cspaceEnd.Name, ospaceEndType.GetReferenceType(), cspaceEnd.RelationshipMultiplicity));
}
CacheEntry.TypesInAssembly.Add(ospaceAssociation);
SessionData.TypesInLoading.Add(ospaceAssociation.FullName, ospaceAssociation);
SessionData.CspaceToOspace.Add(cspaceAssociation, ospaceAssociation);
}
}
}
private StructuralType GetRelationshipEndType(RelationshipEndMember relationshipEndMember)
{
return ((RefType)relationshipEndMember.TypeUsage.EdmType).ElementType;
}
private bool MemberMatchesByConvention(PropertyInfo clrProperty, EdmMember cspaceMember)
{
return clrProperty.Name == cspaceMember.Name;
}
private bool NonPrimitiveMemberMatchesByConvention(PropertyInfo clrProperty, EdmMember cspaceMember)
{
return !clrProperty.PropertyType.IsValueType && !clrProperty.PropertyType.IsAssignableFrom(typeof(string)) && clrProperty.Name == cspaceMember.Name;
}
internal static bool SessionContainsConventionParameters(ObjectItemLoadingSessionData sessionData)
{
return sessionData.EdmItemCollection != null;
}
internal static bool TypesMatchByConvention(Type type, EdmType cspaceType)
{
return type.Name == cspaceType.Name;
}
internal static ObjectItemAssemblyLoader Create(Assembly assembly, ObjectItemLoadingSessionData sessionData)
{
if (!ObjectItemAttributeAssemblyLoader.IsSchemaAttributePresent(assembly))
{
return new ObjectItemConventionAssemblyLoader(assembly, sessionData);
}
else
{
// we were loading in convention mode, and ran into an assembly that can't be loaded by convention
sessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_OSpace_Convention_AttributeAssemblyReferenced(assembly.FullName), null));
return new ObjectItemNoOpAssemblyLoader(assembly, sessionData);
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ControlCachePolicy.cs
- HttpStreamXmlDictionaryReader.cs
- XmlNode.cs
- CompiledXpathExpr.cs
- URLIdentityPermission.cs
- TextElementEnumerator.cs
- ReachFixedPageSerializer.cs
- WizardStepBase.cs
- Rfc2898DeriveBytes.cs
- DateTimeConstantAttribute.cs
- SinglePhaseEnlistment.cs
- XslException.cs
- WmlLinkAdapter.cs
- FrameworkElement.cs
- CdpEqualityComparer.cs
- ClientSection.cs
- FlowPosition.cs
- CipherData.cs
- CorePropertiesFilter.cs
- UnwrappedTypesXmlSerializerManager.cs
- SqlBulkCopy.cs
- MatrixCamera.cs
- PerformanceCounters.cs
- SQLRoleProvider.cs
- ListViewItemSelectionChangedEvent.cs
- DoubleAnimationUsingKeyFrames.cs
- TextParagraph.cs
- RefExpr.cs
- ClientData.cs
- UInt16.cs
- NodeFunctions.cs
- StaticFileHandler.cs
- mansign.cs
- Axis.cs
- SessionIDManager.cs
- DbConnectionStringCommon.cs
- QilVisitor.cs
- Vector3DValueSerializer.cs
- hresults.cs
- SoapReflectionImporter.cs
- WebServiceData.cs
- BitmapMetadata.cs
- Int64Animation.cs
- DataStreams.cs
- PrintDialogException.cs
- DateTimeUtil.cs
- ServiceNameCollection.cs
- PrintControllerWithStatusDialog.cs
- NavigateEvent.cs
- DataGridViewTextBoxCell.cs
- ProtocolsConfigurationHandler.cs
- AsmxEndpointPickerExtension.cs
- TimeoutValidationAttribute.cs
- SqlGenerator.cs
- TreeViewImageKeyConverter.cs
- sqlser.cs
- Vector3DCollectionConverter.cs
- Int32Rect.cs
- ImageMap.cs
- TextTreePropertyUndoUnit.cs
- LazyTextWriterCreator.cs
- SiteMapDataSourceView.cs
- CodeTypeReferenceCollection.cs
- RNGCryptoServiceProvider.cs
- Convert.cs
- MultiTrigger.cs
- ManagementEventArgs.cs
- PartialList.cs
- Int16Storage.cs
- MouseGestureConverter.cs
- EdmRelationshipNavigationPropertyAttribute.cs
- InputReportEventArgs.cs
- XpsFixedDocumentSequenceReaderWriter.cs
- CommandHelper.cs
- ParserHooks.cs
- EndPoint.cs
- SimpleHandlerBuildProvider.cs
- QueryContinueDragEventArgs.cs
- ControlUtil.cs
- HttpConfigurationContext.cs
- DiffuseMaterial.cs
- TableRowsCollectionEditor.cs
- EdmError.cs
- ComponentTray.cs
- AtomMaterializer.cs
- SerialPort.cs
- ClaimTypeRequirement.cs
- TrustManagerMoreInformation.cs
- MenuStrip.cs
- columnmapfactory.cs
- DocumentPage.cs
- UrlMappingsSection.cs
- ClientBuildManagerCallback.cs
- TransformPattern.cs
- GenericTextProperties.cs
- codemethodreferenceexpression.cs
- MatrixValueSerializer.cs
- DrawingGroup.cs
- WsatServiceAddress.cs
- CapabilitiesState.cs