Code:
/ 4.0 / 4.0 / 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. //---------------------------------------------------------------------- // // 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
- PackageProperties.cs
- ClientFactory.cs
- OleDbEnumerator.cs
- TrackingMemoryStreamFactory.cs
- XmlElementCollection.cs
- ObjectViewQueryResultData.cs
- Vector3DAnimationBase.cs
- SoapElementAttribute.cs
- ExtractCollection.cs
- PackageProperties.cs
- ScrollProviderWrapper.cs
- TagPrefixInfo.cs
- DynamicUpdateCommand.cs
- ClrProviderManifest.cs
- XmlSignificantWhitespace.cs
- Journal.cs
- PrintPreviewGraphics.cs
- DateTimeStorage.cs
- HostProtectionException.cs
- SchemaImporter.cs
- GeneratedContractType.cs
- NameTable.cs
- PackageProperties.cs
- NullableBoolConverter.cs
- EasingQuaternionKeyFrame.cs
- Point3D.cs
- AttributeCollection.cs
- OdbcConnectionString.cs
- ConnectionConsumerAttribute.cs
- Pen.cs
- Canvas.cs
- SafeArrayRankMismatchException.cs
- EntityContainerEntitySetDefiningQuery.cs
- TextBlock.cs
- GlyphInfoList.cs
- DataFormats.cs
- GridViewUpdateEventArgs.cs
- EnumDataContract.cs
- ObjectViewEntityCollectionData.cs
- ExceptionTrace.cs
- OrderByQueryOptionExpression.cs
- XmlNotation.cs
- Tokenizer.cs
- DecimalAnimation.cs
- RepeatInfo.cs
- ReferenceEqualityComparer.cs
- BufferedReceiveManager.cs
- ActivitySurrogate.cs
- _BasicClient.cs
- coordinatorfactory.cs
- CodeTypeParameter.cs
- BooleanStorage.cs
- FactoryRecord.cs
- EntitySet.cs
- TreeNodeCollection.cs
- ContextProperty.cs
- ACL.cs
- CoreSwitches.cs
- MatrixTransform.cs
- XPathItem.cs
- SkewTransform.cs
- Type.cs
- listitem.cs
- WmlValidationSummaryAdapter.cs
- RadioButton.cs
- FontWeight.cs
- COAUTHIDENTITY.cs
- RawStylusInputCustomData.cs
- EasingKeyFrames.cs
- SafeViewOfFileHandle.cs
- TableItemProviderWrapper.cs
- IssuedTokensHeader.cs
- TextOnlyOutput.cs
- QueryUtil.cs
- CultureSpecificCharacterBufferRange.cs
- SafePipeHandle.cs
- LinkDescriptor.cs
- ItemList.cs
- ApplyHostConfigurationBehavior.cs
- DbConnectionHelper.cs
- COM2ICategorizePropertiesHandler.cs
- Condition.cs
- SizeValueSerializer.cs
- ProcessingInstructionAction.cs
- ProxyWebPartManager.cs
- SizeChangedInfo.cs
- Menu.cs
- OdbcConnection.cs
- XmlParser.cs
- XsltLoader.cs
- ConstNode.cs
- Utils.cs
- SHA1CryptoServiceProvider.cs
- StickyNoteContentControl.cs
- ErrorRuntimeConfig.cs
- DesignerVerb.cs
- Emitter.cs
- TemplatePropertyEntry.cs
- SoapTypeAttribute.cs
- PageFunction.cs