Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / EntityModelSchemaGenerator.cs / 2 / EntityModelSchemaGenerator.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Diagnostics;
using System.Collections.Generic;
using System.Xml;
using System.Data.Metadata.Edm;
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design.SsdlGenerator;
using System.Reflection;
using System.Data.Common.Utils;
namespace System.Data.Entity.Design
{
///
/// The class creates a default CCMapping between an EntityContainer in S space
/// and an EntityContainer in C space. The Mapping will be created based on the
/// declared types of extents. So Inheritance does not work.
///
public sealed class EntityModelSchemaGenerator
{
private const string ENTITY_CONTAINER_NAME_SUFFIX = "Context";
private const string NAMESPACE_NAME_SUFFIX = "Model";
private const string DEFAULT_NAMESPACE_NAME = "Application";
#region Constructors
///
/// Constructs an EntityModelGenerator
///
/// The Store EntityContainer to create the Model Metadata from.
/// The name to give the namespace. If null, the name of the storeEntityContainer will be used.
/// The name to give the Model EntityContainer. If null, a modified version of the namespace of the of a type referenced in storeEntityContainer will be used.
public EntityModelSchemaGenerator(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName)
{
EDesignUtil.CheckArgumentNull(storeEntityContainer, "storeEntityContainer");
EDesignUtil.CheckStringArgument(namespaceName, "namespaceName");
EDesignUtil.CheckStringArgument(namespaceName, "modelEntityContainerName");
string adjustedNamespaceName = CreateValildModelNamespaceName(namespaceName);
if (adjustedNamespaceName != namespaceName)
{
// the user gave us a bad namespace name
throw EDesignUtil.InvalidNamespaceNameArgument(namespaceName);
}
string adjustedEntityContanierName = CreateModelName(modelEntityContainerName);
if(adjustedEntityContanierName != modelEntityContainerName)
{
throw EDesignUtil.InvalidEntityContainerNameArgument(modelEntityContainerName);
}
Initialize(storeEntityContainer, namespaceName, modelEntityContainerName);
}
private void Initialize(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName)
{
if (!MetadataUtil.IsStoreType(storeEntityContainer))
{
throw EDesignUtil.InvalidStoreEntityContainer(storeEntityContainer.Name, "storeEntityContainer");
}
_storeEntityContainer = storeEntityContainer;
_namespaceName = namespaceName;
_modelEntityContainerName = modelEntityContainerName;
SetupFields();
if (modelEntityContainerName == storeEntityContainer.Name)
{
throw EDesignUtil.DuplicateEntityContainerName(_modelEntityContainerName, _storeEntityContainer.Name);
}
}
///
/// Constructs an EntityModelGenerator
///
///
public EntityModelSchemaGenerator(EntityContainer storeEntityContainer)
{
Initialize(storeEntityContainer, null, null);
}
#endregion
#region Fields
private EntityContainer _storeEntityContainer;
private EntityContainer _modelEntityContainer = null;
private OneToOneMappingSerializer.MappingLookups _mappingLookups = null;
string _namespaceName = null;
string _modelEntityContainerName = null;
private EdmItemCollection _edmItemCollection;
#endregion
#region Properties
///
/// Gets the EntityContainer that was created
///
public EntityContainer EntityContainer
{
get
{
return _modelEntityContainer;
}
}
///
/// Gets the EntityContainer that was created
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public EdmItemCollection EdmItemCollection
{
get
{
return _edmItemCollection;
}
}
#endregion
// responsible for holding all the
// state for a single execution of the Load
// method
private class LoadMethodSessionState
{
public EdmItemCollection EdmItemCollection;
public IList Errors = new List();
public UniqueIdentifierService UsedGlobalModelTypeNames = new UniqueIdentifierService(false);
public UniqueIdentifierService UsedEntitySetBaseNames = new UniqueIdentifierService(false);
public Dictionary FkProperties = new Dictionary();
public Dictionary CandidateCollapsedAssociations = new Dictionary();
public OneToOneMappingSerializer.MappingLookups MappingLookups = new OneToOneMappingSerializer.MappingLookups();
internal void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception e)
{
Debug.Assert(message != null, "message parameter is null");
if (null == e)
{
Errors.Add(new EdmSchemaError(message, (int)errorCode, severity));
}
else
{
Errors.Add(new EdmSchemaError(message, (int)errorCode, severity, e));
}
}
}
#region public methods
///
/// This method reads the s-space metadata objects and creates
/// corosponding c-space metadata objects
///
public IList GenerateMetadata()
{
if (_modelEntityContainer != null)
{
_modelEntityContainer = null;
_mappingLookups = null;
_edmItemCollection = null;
}
LoadMethodSessionState session = new LoadMethodSessionState();
try
{
session.EdmItemCollection = new EdmItemCollection();
List storeAssociationSets = new List();
CollectAllFkProperties(session);
EntityContainer modelEntityContainer = new EntityContainer(_modelEntityContainerName, DataSpace.CSpace);
// create the EntityTypes and EntitySets, and save up the AssociationSets for later.
foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
{
switch (storeSet.BuiltInTypeKind)
{
case BuiltInTypeKind.AssociationSet:
// save these, and create them after the EntityTypes and EntitySets have been created
string errorMessage;
if (!EntityStoreSchemaGenerator.IsFkPartiallyContainedInPK(((AssociationSet)storeSet).ElementType, out errorMessage))
{
storeAssociationSets.Add((AssociationSet)storeSet);
}
else
{
session.AddError(errorMessage, ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Error, null);
}
break;
case BuiltInTypeKind.EntitySet:
EntitySet set = (EntitySet)storeSet;
session.CandidateCollapsedAssociations.Add(set, new OneToOneMappingSerializer.CollapsedEntityAssociationSet(set));
break;
default:
// error
throw EDesignUtil.MissingGenerationPatternForType(storeSet.BuiltInTypeKind);
}
}
foreach (AssociationSet storeAssociationSet in storeAssociationSets)
{
SaveAssociationForCollapsedAssociationCandidate(session, storeAssociationSet);
}
Set associationSetsFromCollapseCandidateRejects = new Set();
IEnumerable invalidCandidates = FindAllInvalidCollapsedAssociationCandidates(session);
// now that we have gone through all of the association sets,
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in invalidCandidates)
{
session.CandidateCollapsedAssociations.Remove(collapsed.EntitySet);
// just create the entity set and save the association set to be added later
EntitySet entitySet = CreateModelEntitySet(session, collapsed.EntitySet);
modelEntityContainer.AddEntitySetBase(entitySet);
associationSetsFromCollapseCandidateRejects.AddRange(collapsed.AssociationSets);
}
// create all the associations for the invalid collapsed entity association candidates
foreach (AssociationSet storeAssociationSet in (IEnumerable)associationSetsFromCollapseCandidateRejects)
{
if (!IsAssociationPartOfCandidateCollapsedAssociation(session, storeAssociationSet))
{
AssociationSet set = CreateModelAssociationSet(session, storeAssociationSet);
modelEntityContainer.AddEntitySetBase(set);
}
}
// save the set that needs to be created and mapped
session.MappingLookups.CollapsedEntityAssociationSets.AddRange(session.CandidateCollapsedAssociations.Values);
// do this in a seperate loop so we are sure all the necessary EntitySets have been created
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.MappingLookups.CollapsedEntityAssociationSets)
{
AssociationSet set = CreateModelAssociationSet(session, collapsed);
modelEntityContainer.AddEntitySetBase(set);
}
if (!EntityStoreSchemaGenerator.HasErrorSeverityErrors(session.Errors))
{
// add them to the collection so they will work if someone wants to use the collection
foreach (EntityType type in session.MappingLookups.StoreEntityTypeToModelEntityType.Values)
{
type.SetReadOnly();
session.EdmItemCollection.AddInternal(type);
}
foreach (AssociationType type in session.MappingLookups.StoreAssociationTypeToModelAssociationType.Values)
{
type.SetReadOnly();
session.EdmItemCollection.AddInternal(type);
}
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet set in session.MappingLookups.CollapsedEntityAssociationSets)
{
set.ModelAssociationSet.ElementType.SetReadOnly();
session.EdmItemCollection.AddInternal(set.ModelAssociationSet.ElementType);
}
modelEntityContainer.SetReadOnly();
session.EdmItemCollection.AddInternal(modelEntityContainer);
_modelEntityContainer = modelEntityContainer;
_mappingLookups = session.MappingLookups;
_edmItemCollection = session.EdmItemCollection;
}
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
// an exception in the code is definitely an error
string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e);
session.AddError(message,
ModelBuilderErrorCode.UnknownError,
EdmSchemaErrorSeverity.Error,
e);
}
else
{
throw;
}
}
return session.Errors;
}
private IEnumerable FindAllInvalidCollapsedAssociationCandidates(LoadMethodSessionState session)
{
Set invalid = new Set();
Dictionary newCandidates = new Dictionary();
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.CandidateCollapsedAssociations.Values)
{
if (!collapsed.MeetsRequirementsForCollapsableAssociation)
{
invalid.Add(collapsed);
}
else
{
newCandidates.Add(collapsed.EntitySet, collapsed);
}
}
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in newCandidates.Values)
{
foreach (AssociationSet set in collapsed.AssociationSets)
{
EntitySet end0Set = set.AssociationSetEnds[0].EntitySet;
EntitySet end1Set = set.AssociationSetEnds[1].EntitySet;
// if both ends of the association are candidates throw both candidates out
// because we can't collapse two entities out
// and we don't know which entity we should collapse
// so we won't collapse either
if (newCandidates.ContainsKey(end0Set) &&
newCandidates.ContainsKey(end1Set))
{
OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed0 = session.CandidateCollapsedAssociations[end0Set];
OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed1 = session.CandidateCollapsedAssociations[end1Set];
invalid.Add(collapsed0);
invalid.Add(collapsed1);
}
}
}
return invalid;
}
private bool IsAssociationPartOfCandidateCollapsedAssociation(LoadMethodSessionState session, AssociationSet storeAssociationSet)
{
foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
{
if (session.CandidateCollapsedAssociations.ContainsKey(end.EntitySet))
{
return true;
}
}
return false;
}
private void SaveAssociationForCollapsedAssociationCandidate(LoadMethodSessionState session, AssociationSet storeAssociationSet)
{
foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
{
OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed;
if (session.CandidateCollapsedAssociations.TryGetValue(end.EntitySet, out collapsed))
{
collapsed.AssociationSets.Add(storeAssociationSet);
}
}
}
private void CollectAllFkProperties(LoadMethodSessionState session)
{
foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
{
if (storeSet.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
{
ReferentialConstraint constraint = OneToOneMappingSerializer.GetReferentialConstraint(((AssociationSet)storeSet));
foreach (EdmProperty property in constraint.ToProperties)
{
if (!session.FkProperties.ContainsKey(property))
{
session.FkProperties.Add(property, ((AssociationSet)storeSet).ElementType);
}
}
}
}
}
///
/// Writes the Schema to xml
///
/// The name of the file to write the xml to.
public void WriteModelSchema(string outputFileName)
{
EDesignUtil.CheckStringArgument(outputFileName, "outputFileName");
CheckValidSchema();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
{
WriteModelSchema(writer);
}
}
///
/// Writes the Schema to xml.
///
/// The XmlWriter to write the xml to.
public void WriteModelSchema(XmlWriter writer)
{
EDesignUtil.CheckArgumentNull(writer, "writer");
CheckValidSchema();
MetadataItemSerializer.WriteXml(writer, _edmItemCollection, _namespaceName);
}
///
/// Writes the cs mapping Schema to xml
///
/// The name of the file to write the xml to.
public void WriteStorageMapping(string outputFileName)
{
EDesignUtil.CheckStringArgument(outputFileName, "outputFileName");
CheckValidSchema();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
{
WriteStorageMapping(writer);
}
}
///
/// Writes the Schema to xml.
///
/// The XmlWriter to write the xml to.
public void WriteStorageMapping(XmlWriter writer)
{
EDesignUtil.CheckArgumentNull(writer, "writer");
CheckValidSchema();
OneToOneMappingSerializer.WriteXml(writer, _mappingLookups, _storeEntityContainer, _modelEntityContainer);
}
#endregion
// Get ModelSchemaNamespace name
private void SetupFields()
{
if( _modelEntityContainerName != null && _namespaceName != null)
{
return;
}
string targetSchemaNamespace = null;
//Try and get the target schema namespace from one of the types or functions defined in the schema
foreach(EntitySetBase type in _storeEntityContainer.BaseEntitySets)
{
targetSchemaNamespace = type.ElementType.NamespaceName;
break;
}
if (string.IsNullOrEmpty(targetSchemaNamespace))
{
// the default
targetSchemaNamespace = DEFAULT_NAMESPACE_NAME;
}
if(_namespaceName == null)
{
// if the schema namespace has 'Target' then replace it with '.Model
int index = targetSchemaNamespace.IndexOf("Target", StringComparison.OrdinalIgnoreCase);
if (index > 0)
{
_namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace.Substring(0, index) + NAMESPACE_NAME_SUFFIX);
}
else
{
// else just append .Model to the name
_namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace + NAMESPACE_NAME_SUFFIX);
}
}
if(_modelEntityContainerName == null)
{
// get default container name
int dotIndex = targetSchemaNamespace.IndexOf('.');
if (dotIndex > 0)
{
_modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, dotIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
}
else
{
_modelEntityContainerName = CreateModelName(targetSchemaNamespace + ENTITY_CONTAINER_NAME_SUFFIX);
}
int targetIndex = _modelEntityContainerName.IndexOf("Target", StringComparison.OrdinalIgnoreCase);
if (targetIndex > 0)
{
_modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, targetIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
}
}
}
private void CheckValidSchema()
{
if (_modelEntityContainer == null)
{
throw EDesignUtil.EntityModelGeneratorSchemaNotLoaded();
}
}
private EntitySet CreateModelEntitySet(LoadMethodSessionState session, EntitySet storeEntitySet)
{
EntityType entity = CreateModelEntity(session, storeEntitySet.ElementType);
string name = CreateModelName(storeEntitySet.Name, session.UsedEntitySetBaseNames);
EntitySet set = new EntitySet(name, null, null, null, entity);
session.MappingLookups.StoreEntitySetToModelEntitySet.Add(storeEntitySet, set);
return set;
}
private EntityType CreateModelEntity(LoadMethodSessionState session, EntityType storeEntityType)
{
Debug.Assert(MetadataUtil.IsStoreType(storeEntityType), "this is not a store type");
Debug.Assert(storeEntityType.BaseType == null, "we are assuming simple generation from a database where no types will have a base type");
EntityType foundEntity;
if (session.MappingLookups.StoreEntityTypeToModelEntityType.TryGetValue(storeEntityType, out foundEntity))
{
// this entity type is used in two different entity sets
return foundEntity;
}
// create all the properties
List members = new List();
List keyMemberNames = new List();
UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false);
string name = CreateModelName(storeEntityType.Name, session.UsedGlobalModelTypeNames);
// Don't want to have a property with the same name as the entity
usedPropertyNames.RegisterUsedIdentifier(name);
foreach (EdmProperty storeProperty in storeEntityType.Properties)
{
// only add non fk properties
EdmMember member;
bool isKey = storeEntityType.KeyMembers.TryGetValue(storeProperty.Name, false, out member);
AssociationType association;
bool isPartOfRelationship = session.FkProperties.TryGetValue(storeProperty, out association);
if (!isPartOfRelationship || isKey)
{
EdmProperty property = CreateModelProperty(session, _namespaceName + "." + name, storeProperty, usedPropertyNames);
members.Add(property);
if (isKey)
{
keyMemberNames.Add(property.Name);
}
}
}
EntityType entity = new EntityType(name,
_namespaceName,
DataSpace.CSpace,
keyMemberNames,
members);
session.MappingLookups.StoreEntityTypeToModelEntityType.Add(storeEntityType, entity);
return entity;
}
private EdmProperty CreateModelProperty(LoadMethodSessionState session, string declaringTypeName, EdmProperty storeProperty, UniqueIdentifierService usedPropertyNames)
{
string name = CreateModelName(storeProperty.Name, usedPropertyNames);
TypeUsage cspaceTypeUsage = storeProperty.TypeUsage.GetModelTypeUsage();
EdmProperty property = new EdmProperty(name, cspaceTypeUsage);
session.MappingLookups.StoreEdmPropertyToModelEdmProperty.Add(storeProperty, property);
return property;
}
private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsedAssociationSet)
{
// create the association
string associationName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedGlobalModelTypeNames);
AssociationType association = new AssociationType(associationName,
_namespaceName, DataSpace.CSpace);
// create the association set
string associationSetName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedEntitySetBaseNames);
AssociationSet set = new AssociationSet(associationSetName, association);
// create the association and association set end members
UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
for(int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++)
{
AssociationSetEnd storeEnd;
RelationshipMultiplicity multiplicity;
OperationAction deleteBehavior;
collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior);
AssociationEndMember end = CreateAssociationEndMember(session, storeEnd.CorrespondingAssociationEndMember, usedEndMemberNames, multiplicity, deleteBehavior);
association.AddMember(end);
EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet];
AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end);
set.AddAssociationSetEnd(setEnd);
session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, setEnd);
}
// don't need a referential constraint
CreateModelNavigationProperties(session, association);
collapsedAssociationSet.ModelAssociationSet = set;
return set;
}
private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, AssociationSet storeAssociationSet)
{
AssociationType association;
// we will get a value when the same association is used for multiple association sets
if (! session.MappingLookups.StoreAssociationTypeToModelAssociationType.TryGetValue(storeAssociationSet.ElementType, out association))
{
association = CreateModelAssociation(session, storeAssociationSet.ElementType);
session.MappingLookups.StoreAssociationTypeToModelAssociationType.Add(storeAssociationSet.ElementType, association);
}
string name = CreateModelName(storeAssociationSet.Name, session.UsedEntitySetBaseNames);
AssociationSet set = new AssociationSet(name, association);
foreach(AssociationSetEnd storeEnd in storeAssociationSet.AssociationSetEnds)
{
AssociationSetEnd end = CreateModelAssociationSetEnd(session, storeEnd, set);
session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, end);
set.AddAssociationSetEnd(end);
}
session.MappingLookups.StoreAssociationSetToModelAssociationSet.Add(storeAssociationSet, set);
return set;
}
private AssociationSetEnd CreateModelAssociationSetEnd(LoadMethodSessionState session, AssociationSetEnd storeEnd, AssociationSet parentModelAssociationSet)
{
AssociationEndMember associationEnd = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[storeEnd.CorrespondingAssociationEndMember];
EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet];
string role = associationEnd.Name;
AssociationSetEnd end = new AssociationSetEnd(entitySet, parentModelAssociationSet, associationEnd);
return end;
}
private AssociationType CreateModelAssociation(LoadMethodSessionState session, AssociationType storeAssociationType)
{
UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
string name = CreateModelName(storeAssociationType.Name, session.UsedGlobalModelTypeNames);
AssociationType association = new AssociationType(name,
_namespaceName,
DataSpace.CSpace);
foreach (AssociationEndMember storeEndMember in storeAssociationType.RelationshipEndMembers)
{
AssociationEndMember end = CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames);
session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember.Add(storeEndMember, end);
association.AddMember(end);
}
ReferentialConstraint constraint = CreateReferentialConstraint(session, storeAssociationType);
if (constraint != null)
{
association.AddReferentialConstraint(constraint);
}
CreateModelNavigationProperties(session, association);
return association;
}
private ReferentialConstraint CreateReferentialConstraint(LoadMethodSessionState session, AssociationType storeAssociation)
{
Debug.Assert(session != null, "session parameter is null");
Debug.Assert(storeAssociation != null, "storeAssociation parameter is null");
Debug.Assert(storeAssociation.ReferentialConstraints.Count <= 1, "We don't have a reason to have more than one constraint yet");
// does the store have any constraints
if (storeAssociation.ReferentialConstraints.Count == 0)
{
return null;
}
ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];
Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts");
Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?");
Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType");
EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType;
bool toPropertiesAreKey = toType.KeyMembers.Contains(storeConstraint.ToProperties[0]);
// has an non primary key in the FK, this means all the FK are not PK
// since we already checked the other condition which is the FK partially contains PK in the
// funciton IsFkPartiallyContainedInPK, so no referential constraints for this
if (!toPropertiesAreKey)
{
return null;
}
// we need a constraint so lets build it
int count = storeConstraint.FromProperties.Count;
EdmProperty[] fromProperties = new EdmProperty[count];
EdmProperty[] toProperties = new EdmProperty[count];
AssociationEndMember fromRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.FromRole];
AssociationEndMember toRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.ToRole];
for (int index = 0; index < count; index++)
{
fromProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.FromProperties[index]];
toProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.ToProperties[index]];
}
ReferentialConstraint newConstraint = new ReferentialConstraint(
fromRole,
toRole,
fromProperties,
toProperties);
return newConstraint;
}
private void CreateModelNavigationProperties(LoadMethodSessionState session, AssociationType association)
{
Debug.Assert(association.Members.Count == 2, "this code assumes two ends");
AssociationEndMember end1 = (AssociationEndMember)association.Members[0];
AssociationEndMember end2 = (AssociationEndMember)association.Members[1];
CreateModelNavigationProperty(session, end1, end2);
CreateModelNavigationProperty(session, end2, end1);
}
private void CreateModelNavigationProperty(LoadMethodSessionState session, AssociationEndMember from, AssociationEndMember to)
{
EntityType entityType = (EntityType)((RefType)from.TypeUsage.EdmType).ElementType;
UniqueIdentifierService usedMemberNames = new UniqueIdentifierService(false);
LoadNameLookupWithUsedMemberNames(entityType, usedMemberNames);
string name = CreateModelName(to.Name, usedMemberNames);
NavigationProperty navigationProperty = new NavigationProperty(name, to.TypeUsage);
navigationProperty.RelationshipType = (AssociationType)to.DeclaringType;
navigationProperty.ToEndMember = to;
navigationProperty.FromEndMember = from;
entityType.AddMember(navigationProperty);
}
private void LoadNameLookupWithUsedMemberNames(EntityType entityType, UniqueIdentifierService usedMemberNames)
{
// a property should not have the same name as its entity
usedMemberNames.RegisterUsedIdentifier(entityType.Name);
foreach (EdmMember member in entityType.Members)
{
usedMemberNames.RegisterUsedIdentifier(member.Name);
}
}
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames)
{
return CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames, storeEndMember.RelationshipMultiplicity, storeEndMember.DeleteBehavior);
}
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames, RelationshipMultiplicity multiplicityOverride, OperationAction deleteBehaviorOverride)
{
Debug.Assert(storeEndMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "The type is not a ref type");
Debug.Assert(((RefType)storeEndMember.TypeUsage.EdmType).ElementType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "the ref is not holding on to an EntityType");
EntityType storeEntityType = ((EntityType)((RefType)storeEndMember.TypeUsage.EdmType).ElementType);
EntityType modelEntityType = session.MappingLookups.StoreEntityTypeToModelEntityType[storeEntityType];
string name = CreateModelName(storeEndMember.Name, usedEndMemberNames);
AssociationEndMember end = new AssociationEndMember(name, modelEntityType.GetReferenceType(), multiplicityOverride);
end.DeleteBehavior = deleteBehaviorOverride;
return end;
}
private string CreateModelName(string storeName, UniqueIdentifierService usedNames)
{
string newName = CreateModelName(storeName);
newName = usedNames.AdjustIdentifier(newName);
return newName;
}
private static string CreateValildModelNamespaceName(string storeNamespaceName)
{
return CreateValidNamespaceName(storeNamespaceName, 'C');
}
internal static string CreateValidNamespaceName(string storeNamespaceName, char appendToFrontIfFirstCharIsInvalid)
{
List namespaceParts = new List();
foreach (string sPart in storeNamespaceName.Split(new char[] { '.' }))
{
// each part of a namespace needs to be a valid
// cspace name
namespaceParts.Add(CreateValidEcmaName(sPart, appendToFrontIfFirstCharIsInvalid));
}
string modelNamespaceName = "";
for (int i = 0; i < namespaceParts.Count - 1; i++)
{
modelNamespaceName += namespaceParts[i] + ".";
}
modelNamespaceName += namespaceParts[namespaceParts.Count - 1];
// We might get a clash in names if ssdl has two types named #table and $table. Both will generate C_table
// We leave it to the calling method to resolve any name clashes
return modelNamespaceName;
}
//This method maps invalid characters such as &^%,etc in order to generate valid names
private static string CreateModelName(string storeName)
{
return CreateValidEcmaName(storeName, 'C');
}
internal static string CreateValidEcmaName(string name, char appendToFrontIfFirstCharIsInvalid)
{
char[] ecmaNameArray = name.ToCharArray();
for (int i = 0; i < ecmaNameArray.Length; i++)
{
// replace non -(letters or digits) with _ ( underscore )
if (!char.IsLetterOrDigit(ecmaNameArray[i]))
{
ecmaNameArray[i] = '_';
}
}
string ecmaName = new string(ecmaNameArray);
// the first letter in a part should only be a char
if (!char.IsLetter(ecmaName[0]))
{
ecmaName = appendToFrontIfFirstCharIsInvalid + ecmaName;
}
return ecmaName;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Diagnostics;
using System.Collections.Generic;
using System.Xml;
using System.Data.Metadata.Edm;
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design.SsdlGenerator;
using System.Reflection;
using System.Data.Common.Utils;
namespace System.Data.Entity.Design
{
///
/// The class creates a default CCMapping between an EntityContainer in S space
/// and an EntityContainer in C space. The Mapping will be created based on the
/// declared types of extents. So Inheritance does not work.
///
public sealed class EntityModelSchemaGenerator
{
private const string ENTITY_CONTAINER_NAME_SUFFIX = "Context";
private const string NAMESPACE_NAME_SUFFIX = "Model";
private const string DEFAULT_NAMESPACE_NAME = "Application";
#region Constructors
///
/// Constructs an EntityModelGenerator
///
/// The Store EntityContainer to create the Model Metadata from.
/// The name to give the namespace. If null, the name of the storeEntityContainer will be used.
/// The name to give the Model EntityContainer. If null, a modified version of the namespace of the of a type referenced in storeEntityContainer will be used.
public EntityModelSchemaGenerator(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName)
{
EDesignUtil.CheckArgumentNull(storeEntityContainer, "storeEntityContainer");
EDesignUtil.CheckStringArgument(namespaceName, "namespaceName");
EDesignUtil.CheckStringArgument(namespaceName, "modelEntityContainerName");
string adjustedNamespaceName = CreateValildModelNamespaceName(namespaceName);
if (adjustedNamespaceName != namespaceName)
{
// the user gave us a bad namespace name
throw EDesignUtil.InvalidNamespaceNameArgument(namespaceName);
}
string adjustedEntityContanierName = CreateModelName(modelEntityContainerName);
if(adjustedEntityContanierName != modelEntityContainerName)
{
throw EDesignUtil.InvalidEntityContainerNameArgument(modelEntityContainerName);
}
Initialize(storeEntityContainer, namespaceName, modelEntityContainerName);
}
private void Initialize(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName)
{
if (!MetadataUtil.IsStoreType(storeEntityContainer))
{
throw EDesignUtil.InvalidStoreEntityContainer(storeEntityContainer.Name, "storeEntityContainer");
}
_storeEntityContainer = storeEntityContainer;
_namespaceName = namespaceName;
_modelEntityContainerName = modelEntityContainerName;
SetupFields();
if (modelEntityContainerName == storeEntityContainer.Name)
{
throw EDesignUtil.DuplicateEntityContainerName(_modelEntityContainerName, _storeEntityContainer.Name);
}
}
///
/// Constructs an EntityModelGenerator
///
///
public EntityModelSchemaGenerator(EntityContainer storeEntityContainer)
{
Initialize(storeEntityContainer, null, null);
}
#endregion
#region Fields
private EntityContainer _storeEntityContainer;
private EntityContainer _modelEntityContainer = null;
private OneToOneMappingSerializer.MappingLookups _mappingLookups = null;
string _namespaceName = null;
string _modelEntityContainerName = null;
private EdmItemCollection _edmItemCollection;
#endregion
#region Properties
///
/// Gets the EntityContainer that was created
///
public EntityContainer EntityContainer
{
get
{
return _modelEntityContainer;
}
}
///
/// Gets the EntityContainer that was created
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public EdmItemCollection EdmItemCollection
{
get
{
return _edmItemCollection;
}
}
#endregion
// responsible for holding all the
// state for a single execution of the Load
// method
private class LoadMethodSessionState
{
public EdmItemCollection EdmItemCollection;
public IList Errors = new List();
public UniqueIdentifierService UsedGlobalModelTypeNames = new UniqueIdentifierService(false);
public UniqueIdentifierService UsedEntitySetBaseNames = new UniqueIdentifierService(false);
public Dictionary FkProperties = new Dictionary();
public Dictionary CandidateCollapsedAssociations = new Dictionary();
public OneToOneMappingSerializer.MappingLookups MappingLookups = new OneToOneMappingSerializer.MappingLookups();
internal void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception e)
{
Debug.Assert(message != null, "message parameter is null");
if (null == e)
{
Errors.Add(new EdmSchemaError(message, (int)errorCode, severity));
}
else
{
Errors.Add(new EdmSchemaError(message, (int)errorCode, severity, e));
}
}
}
#region public methods
///
/// This method reads the s-space metadata objects and creates
/// corosponding c-space metadata objects
///
public IList GenerateMetadata()
{
if (_modelEntityContainer != null)
{
_modelEntityContainer = null;
_mappingLookups = null;
_edmItemCollection = null;
}
LoadMethodSessionState session = new LoadMethodSessionState();
try
{
session.EdmItemCollection = new EdmItemCollection();
List storeAssociationSets = new List();
CollectAllFkProperties(session);
EntityContainer modelEntityContainer = new EntityContainer(_modelEntityContainerName, DataSpace.CSpace);
// create the EntityTypes and EntitySets, and save up the AssociationSets for later.
foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
{
switch (storeSet.BuiltInTypeKind)
{
case BuiltInTypeKind.AssociationSet:
// save these, and create them after the EntityTypes and EntitySets have been created
string errorMessage;
if (!EntityStoreSchemaGenerator.IsFkPartiallyContainedInPK(((AssociationSet)storeSet).ElementType, out errorMessage))
{
storeAssociationSets.Add((AssociationSet)storeSet);
}
else
{
session.AddError(errorMessage, ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Error, null);
}
break;
case BuiltInTypeKind.EntitySet:
EntitySet set = (EntitySet)storeSet;
session.CandidateCollapsedAssociations.Add(set, new OneToOneMappingSerializer.CollapsedEntityAssociationSet(set));
break;
default:
// error
throw EDesignUtil.MissingGenerationPatternForType(storeSet.BuiltInTypeKind);
}
}
foreach (AssociationSet storeAssociationSet in storeAssociationSets)
{
SaveAssociationForCollapsedAssociationCandidate(session, storeAssociationSet);
}
Set associationSetsFromCollapseCandidateRejects = new Set();
IEnumerable invalidCandidates = FindAllInvalidCollapsedAssociationCandidates(session);
// now that we have gone through all of the association sets,
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in invalidCandidates)
{
session.CandidateCollapsedAssociations.Remove(collapsed.EntitySet);
// just create the entity set and save the association set to be added later
EntitySet entitySet = CreateModelEntitySet(session, collapsed.EntitySet);
modelEntityContainer.AddEntitySetBase(entitySet);
associationSetsFromCollapseCandidateRejects.AddRange(collapsed.AssociationSets);
}
// create all the associations for the invalid collapsed entity association candidates
foreach (AssociationSet storeAssociationSet in (IEnumerable)associationSetsFromCollapseCandidateRejects)
{
if (!IsAssociationPartOfCandidateCollapsedAssociation(session, storeAssociationSet))
{
AssociationSet set = CreateModelAssociationSet(session, storeAssociationSet);
modelEntityContainer.AddEntitySetBase(set);
}
}
// save the set that needs to be created and mapped
session.MappingLookups.CollapsedEntityAssociationSets.AddRange(session.CandidateCollapsedAssociations.Values);
// do this in a seperate loop so we are sure all the necessary EntitySets have been created
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.MappingLookups.CollapsedEntityAssociationSets)
{
AssociationSet set = CreateModelAssociationSet(session, collapsed);
modelEntityContainer.AddEntitySetBase(set);
}
if (!EntityStoreSchemaGenerator.HasErrorSeverityErrors(session.Errors))
{
// add them to the collection so they will work if someone wants to use the collection
foreach (EntityType type in session.MappingLookups.StoreEntityTypeToModelEntityType.Values)
{
type.SetReadOnly();
session.EdmItemCollection.AddInternal(type);
}
foreach (AssociationType type in session.MappingLookups.StoreAssociationTypeToModelAssociationType.Values)
{
type.SetReadOnly();
session.EdmItemCollection.AddInternal(type);
}
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet set in session.MappingLookups.CollapsedEntityAssociationSets)
{
set.ModelAssociationSet.ElementType.SetReadOnly();
session.EdmItemCollection.AddInternal(set.ModelAssociationSet.ElementType);
}
modelEntityContainer.SetReadOnly();
session.EdmItemCollection.AddInternal(modelEntityContainer);
_modelEntityContainer = modelEntityContainer;
_mappingLookups = session.MappingLookups;
_edmItemCollection = session.EdmItemCollection;
}
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
// an exception in the code is definitely an error
string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e);
session.AddError(message,
ModelBuilderErrorCode.UnknownError,
EdmSchemaErrorSeverity.Error,
e);
}
else
{
throw;
}
}
return session.Errors;
}
private IEnumerable FindAllInvalidCollapsedAssociationCandidates(LoadMethodSessionState session)
{
Set invalid = new Set();
Dictionary newCandidates = new Dictionary();
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.CandidateCollapsedAssociations.Values)
{
if (!collapsed.MeetsRequirementsForCollapsableAssociation)
{
invalid.Add(collapsed);
}
else
{
newCandidates.Add(collapsed.EntitySet, collapsed);
}
}
foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in newCandidates.Values)
{
foreach (AssociationSet set in collapsed.AssociationSets)
{
EntitySet end0Set = set.AssociationSetEnds[0].EntitySet;
EntitySet end1Set = set.AssociationSetEnds[1].EntitySet;
// if both ends of the association are candidates throw both candidates out
// because we can't collapse two entities out
// and we don't know which entity we should collapse
// so we won't collapse either
if (newCandidates.ContainsKey(end0Set) &&
newCandidates.ContainsKey(end1Set))
{
OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed0 = session.CandidateCollapsedAssociations[end0Set];
OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed1 = session.CandidateCollapsedAssociations[end1Set];
invalid.Add(collapsed0);
invalid.Add(collapsed1);
}
}
}
return invalid;
}
private bool IsAssociationPartOfCandidateCollapsedAssociation(LoadMethodSessionState session, AssociationSet storeAssociationSet)
{
foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
{
if (session.CandidateCollapsedAssociations.ContainsKey(end.EntitySet))
{
return true;
}
}
return false;
}
private void SaveAssociationForCollapsedAssociationCandidate(LoadMethodSessionState session, AssociationSet storeAssociationSet)
{
foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
{
OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed;
if (session.CandidateCollapsedAssociations.TryGetValue(end.EntitySet, out collapsed))
{
collapsed.AssociationSets.Add(storeAssociationSet);
}
}
}
private void CollectAllFkProperties(LoadMethodSessionState session)
{
foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
{
if (storeSet.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
{
ReferentialConstraint constraint = OneToOneMappingSerializer.GetReferentialConstraint(((AssociationSet)storeSet));
foreach (EdmProperty property in constraint.ToProperties)
{
if (!session.FkProperties.ContainsKey(property))
{
session.FkProperties.Add(property, ((AssociationSet)storeSet).ElementType);
}
}
}
}
}
///
/// Writes the Schema to xml
///
/// The name of the file to write the xml to.
public void WriteModelSchema(string outputFileName)
{
EDesignUtil.CheckStringArgument(outputFileName, "outputFileName");
CheckValidSchema();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
{
WriteModelSchema(writer);
}
}
///
/// Writes the Schema to xml.
///
/// The XmlWriter to write the xml to.
public void WriteModelSchema(XmlWriter writer)
{
EDesignUtil.CheckArgumentNull(writer, "writer");
CheckValidSchema();
MetadataItemSerializer.WriteXml(writer, _edmItemCollection, _namespaceName);
}
///
/// Writes the cs mapping Schema to xml
///
/// The name of the file to write the xml to.
public void WriteStorageMapping(string outputFileName)
{
EDesignUtil.CheckStringArgument(outputFileName, "outputFileName");
CheckValidSchema();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
{
WriteStorageMapping(writer);
}
}
///
/// Writes the Schema to xml.
///
/// The XmlWriter to write the xml to.
public void WriteStorageMapping(XmlWriter writer)
{
EDesignUtil.CheckArgumentNull(writer, "writer");
CheckValidSchema();
OneToOneMappingSerializer.WriteXml(writer, _mappingLookups, _storeEntityContainer, _modelEntityContainer);
}
#endregion
// Get ModelSchemaNamespace name
private void SetupFields()
{
if( _modelEntityContainerName != null && _namespaceName != null)
{
return;
}
string targetSchemaNamespace = null;
//Try and get the target schema namespace from one of the types or functions defined in the schema
foreach(EntitySetBase type in _storeEntityContainer.BaseEntitySets)
{
targetSchemaNamespace = type.ElementType.NamespaceName;
break;
}
if (string.IsNullOrEmpty(targetSchemaNamespace))
{
// the default
targetSchemaNamespace = DEFAULT_NAMESPACE_NAME;
}
if(_namespaceName == null)
{
// if the schema namespace has 'Target' then replace it with '.Model
int index = targetSchemaNamespace.IndexOf("Target", StringComparison.OrdinalIgnoreCase);
if (index > 0)
{
_namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace.Substring(0, index) + NAMESPACE_NAME_SUFFIX);
}
else
{
// else just append .Model to the name
_namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace + NAMESPACE_NAME_SUFFIX);
}
}
if(_modelEntityContainerName == null)
{
// get default container name
int dotIndex = targetSchemaNamespace.IndexOf('.');
if (dotIndex > 0)
{
_modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, dotIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
}
else
{
_modelEntityContainerName = CreateModelName(targetSchemaNamespace + ENTITY_CONTAINER_NAME_SUFFIX);
}
int targetIndex = _modelEntityContainerName.IndexOf("Target", StringComparison.OrdinalIgnoreCase);
if (targetIndex > 0)
{
_modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, targetIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
}
}
}
private void CheckValidSchema()
{
if (_modelEntityContainer == null)
{
throw EDesignUtil.EntityModelGeneratorSchemaNotLoaded();
}
}
private EntitySet CreateModelEntitySet(LoadMethodSessionState session, EntitySet storeEntitySet)
{
EntityType entity = CreateModelEntity(session, storeEntitySet.ElementType);
string name = CreateModelName(storeEntitySet.Name, session.UsedEntitySetBaseNames);
EntitySet set = new EntitySet(name, null, null, null, entity);
session.MappingLookups.StoreEntitySetToModelEntitySet.Add(storeEntitySet, set);
return set;
}
private EntityType CreateModelEntity(LoadMethodSessionState session, EntityType storeEntityType)
{
Debug.Assert(MetadataUtil.IsStoreType(storeEntityType), "this is not a store type");
Debug.Assert(storeEntityType.BaseType == null, "we are assuming simple generation from a database where no types will have a base type");
EntityType foundEntity;
if (session.MappingLookups.StoreEntityTypeToModelEntityType.TryGetValue(storeEntityType, out foundEntity))
{
// this entity type is used in two different entity sets
return foundEntity;
}
// create all the properties
List members = new List();
List keyMemberNames = new List();
UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false);
string name = CreateModelName(storeEntityType.Name, session.UsedGlobalModelTypeNames);
// Don't want to have a property with the same name as the entity
usedPropertyNames.RegisterUsedIdentifier(name);
foreach (EdmProperty storeProperty in storeEntityType.Properties)
{
// only add non fk properties
EdmMember member;
bool isKey = storeEntityType.KeyMembers.TryGetValue(storeProperty.Name, false, out member);
AssociationType association;
bool isPartOfRelationship = session.FkProperties.TryGetValue(storeProperty, out association);
if (!isPartOfRelationship || isKey)
{
EdmProperty property = CreateModelProperty(session, _namespaceName + "." + name, storeProperty, usedPropertyNames);
members.Add(property);
if (isKey)
{
keyMemberNames.Add(property.Name);
}
}
}
EntityType entity = new EntityType(name,
_namespaceName,
DataSpace.CSpace,
keyMemberNames,
members);
session.MappingLookups.StoreEntityTypeToModelEntityType.Add(storeEntityType, entity);
return entity;
}
private EdmProperty CreateModelProperty(LoadMethodSessionState session, string declaringTypeName, EdmProperty storeProperty, UniqueIdentifierService usedPropertyNames)
{
string name = CreateModelName(storeProperty.Name, usedPropertyNames);
TypeUsage cspaceTypeUsage = storeProperty.TypeUsage.GetModelTypeUsage();
EdmProperty property = new EdmProperty(name, cspaceTypeUsage);
session.MappingLookups.StoreEdmPropertyToModelEdmProperty.Add(storeProperty, property);
return property;
}
private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsedAssociationSet)
{
// create the association
string associationName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedGlobalModelTypeNames);
AssociationType association = new AssociationType(associationName,
_namespaceName, DataSpace.CSpace);
// create the association set
string associationSetName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedEntitySetBaseNames);
AssociationSet set = new AssociationSet(associationSetName, association);
// create the association and association set end members
UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
for(int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++)
{
AssociationSetEnd storeEnd;
RelationshipMultiplicity multiplicity;
OperationAction deleteBehavior;
collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior);
AssociationEndMember end = CreateAssociationEndMember(session, storeEnd.CorrespondingAssociationEndMember, usedEndMemberNames, multiplicity, deleteBehavior);
association.AddMember(end);
EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet];
AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end);
set.AddAssociationSetEnd(setEnd);
session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, setEnd);
}
// don't need a referential constraint
CreateModelNavigationProperties(session, association);
collapsedAssociationSet.ModelAssociationSet = set;
return set;
}
private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, AssociationSet storeAssociationSet)
{
AssociationType association;
// we will get a value when the same association is used for multiple association sets
if (! session.MappingLookups.StoreAssociationTypeToModelAssociationType.TryGetValue(storeAssociationSet.ElementType, out association))
{
association = CreateModelAssociation(session, storeAssociationSet.ElementType);
session.MappingLookups.StoreAssociationTypeToModelAssociationType.Add(storeAssociationSet.ElementType, association);
}
string name = CreateModelName(storeAssociationSet.Name, session.UsedEntitySetBaseNames);
AssociationSet set = new AssociationSet(name, association);
foreach(AssociationSetEnd storeEnd in storeAssociationSet.AssociationSetEnds)
{
AssociationSetEnd end = CreateModelAssociationSetEnd(session, storeEnd, set);
session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, end);
set.AddAssociationSetEnd(end);
}
session.MappingLookups.StoreAssociationSetToModelAssociationSet.Add(storeAssociationSet, set);
return set;
}
private AssociationSetEnd CreateModelAssociationSetEnd(LoadMethodSessionState session, AssociationSetEnd storeEnd, AssociationSet parentModelAssociationSet)
{
AssociationEndMember associationEnd = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[storeEnd.CorrespondingAssociationEndMember];
EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet];
string role = associationEnd.Name;
AssociationSetEnd end = new AssociationSetEnd(entitySet, parentModelAssociationSet, associationEnd);
return end;
}
private AssociationType CreateModelAssociation(LoadMethodSessionState session, AssociationType storeAssociationType)
{
UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
string name = CreateModelName(storeAssociationType.Name, session.UsedGlobalModelTypeNames);
AssociationType association = new AssociationType(name,
_namespaceName,
DataSpace.CSpace);
foreach (AssociationEndMember storeEndMember in storeAssociationType.RelationshipEndMembers)
{
AssociationEndMember end = CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames);
session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember.Add(storeEndMember, end);
association.AddMember(end);
}
ReferentialConstraint constraint = CreateReferentialConstraint(session, storeAssociationType);
if (constraint != null)
{
association.AddReferentialConstraint(constraint);
}
CreateModelNavigationProperties(session, association);
return association;
}
private ReferentialConstraint CreateReferentialConstraint(LoadMethodSessionState session, AssociationType storeAssociation)
{
Debug.Assert(session != null, "session parameter is null");
Debug.Assert(storeAssociation != null, "storeAssociation parameter is null");
Debug.Assert(storeAssociation.ReferentialConstraints.Count <= 1, "We don't have a reason to have more than one constraint yet");
// does the store have any constraints
if (storeAssociation.ReferentialConstraints.Count == 0)
{
return null;
}
ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];
Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts");
Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?");
Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType");
EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType;
bool toPropertiesAreKey = toType.KeyMembers.Contains(storeConstraint.ToProperties[0]);
// has an non primary key in the FK, this means all the FK are not PK
// since we already checked the other condition which is the FK partially contains PK in the
// funciton IsFkPartiallyContainedInPK, so no referential constraints for this
if (!toPropertiesAreKey)
{
return null;
}
// we need a constraint so lets build it
int count = storeConstraint.FromProperties.Count;
EdmProperty[] fromProperties = new EdmProperty[count];
EdmProperty[] toProperties = new EdmProperty[count];
AssociationEndMember fromRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.FromRole];
AssociationEndMember toRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.ToRole];
for (int index = 0; index < count; index++)
{
fromProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.FromProperties[index]];
toProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.ToProperties[index]];
}
ReferentialConstraint newConstraint = new ReferentialConstraint(
fromRole,
toRole,
fromProperties,
toProperties);
return newConstraint;
}
private void CreateModelNavigationProperties(LoadMethodSessionState session, AssociationType association)
{
Debug.Assert(association.Members.Count == 2, "this code assumes two ends");
AssociationEndMember end1 = (AssociationEndMember)association.Members[0];
AssociationEndMember end2 = (AssociationEndMember)association.Members[1];
CreateModelNavigationProperty(session, end1, end2);
CreateModelNavigationProperty(session, end2, end1);
}
private void CreateModelNavigationProperty(LoadMethodSessionState session, AssociationEndMember from, AssociationEndMember to)
{
EntityType entityType = (EntityType)((RefType)from.TypeUsage.EdmType).ElementType;
UniqueIdentifierService usedMemberNames = new UniqueIdentifierService(false);
LoadNameLookupWithUsedMemberNames(entityType, usedMemberNames);
string name = CreateModelName(to.Name, usedMemberNames);
NavigationProperty navigationProperty = new NavigationProperty(name, to.TypeUsage);
navigationProperty.RelationshipType = (AssociationType)to.DeclaringType;
navigationProperty.ToEndMember = to;
navigationProperty.FromEndMember = from;
entityType.AddMember(navigationProperty);
}
private void LoadNameLookupWithUsedMemberNames(EntityType entityType, UniqueIdentifierService usedMemberNames)
{
// a property should not have the same name as its entity
usedMemberNames.RegisterUsedIdentifier(entityType.Name);
foreach (EdmMember member in entityType.Members)
{
usedMemberNames.RegisterUsedIdentifier(member.Name);
}
}
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames)
{
return CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames, storeEndMember.RelationshipMultiplicity, storeEndMember.DeleteBehavior);
}
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames, RelationshipMultiplicity multiplicityOverride, OperationAction deleteBehaviorOverride)
{
Debug.Assert(storeEndMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "The type is not a ref type");
Debug.Assert(((RefType)storeEndMember.TypeUsage.EdmType).ElementType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "the ref is not holding on to an EntityType");
EntityType storeEntityType = ((EntityType)((RefType)storeEndMember.TypeUsage.EdmType).ElementType);
EntityType modelEntityType = session.MappingLookups.StoreEntityTypeToModelEntityType[storeEntityType];
string name = CreateModelName(storeEndMember.Name, usedEndMemberNames);
AssociationEndMember end = new AssociationEndMember(name, modelEntityType.GetReferenceType(), multiplicityOverride);
end.DeleteBehavior = deleteBehaviorOverride;
return end;
}
private string CreateModelName(string storeName, UniqueIdentifierService usedNames)
{
string newName = CreateModelName(storeName);
newName = usedNames.AdjustIdentifier(newName);
return newName;
}
private static string CreateValildModelNamespaceName(string storeNamespaceName)
{
return CreateValidNamespaceName(storeNamespaceName, 'C');
}
internal static string CreateValidNamespaceName(string storeNamespaceName, char appendToFrontIfFirstCharIsInvalid)
{
List namespaceParts = new List();
foreach (string sPart in storeNamespaceName.Split(new char[] { '.' }))
{
// each part of a namespace needs to be a valid
// cspace name
namespaceParts.Add(CreateValidEcmaName(sPart, appendToFrontIfFirstCharIsInvalid));
}
string modelNamespaceName = "";
for (int i = 0; i < namespaceParts.Count - 1; i++)
{
modelNamespaceName += namespaceParts[i] + ".";
}
modelNamespaceName += namespaceParts[namespaceParts.Count - 1];
// We might get a clash in names if ssdl has two types named #table and $table. Both will generate C_table
// We leave it to the calling method to resolve any name clashes
return modelNamespaceName;
}
//This method maps invalid characters such as &^%,etc in order to generate valid names
private static string CreateModelName(string storeName)
{
return CreateValidEcmaName(storeName, 'C');
}
internal static string CreateValidEcmaName(string name, char appendToFrontIfFirstCharIsInvalid)
{
char[] ecmaNameArray = name.ToCharArray();
for (int i = 0; i < ecmaNameArray.Length; i++)
{
// replace non -(letters or digits) with _ ( underscore )
if (!char.IsLetterOrDigit(ecmaNameArray[i]))
{
ecmaNameArray[i] = '_';
}
}
string ecmaName = new string(ecmaNameArray);
// the first letter in a part should only be a char
if (!char.IsLetter(ecmaName[0]))
{
ecmaName = appendToFrontIfFirstCharIsInvalid + ecmaName;
}
return ecmaName;
}
}
}
// 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
- PersonalizationStateQuery.cs
- PropertyAccessVisitor.cs
- Thread.cs
- ResourceManager.cs
- future.cs
- SqlDataAdapter.cs
- BrowserDefinitionCollection.cs
- StateMachineSubscriptionManager.cs
- RoleGroup.cs
- Int32Converter.cs
- SqlParameterizer.cs
- ProfileSettings.cs
- Globals.cs
- DrawingContextDrawingContextWalker.cs
- AdjustableArrowCap.cs
- SqlTypeConverter.cs
- UriSection.cs
- MetabaseSettingsIis7.cs
- SelectedGridItemChangedEvent.cs
- EFTableProvider.cs
- TableRowCollection.cs
- TraceSection.cs
- UseAttributeSetsAction.cs
- ListBox.cs
- MulticastOption.cs
- WebPartRestoreVerb.cs
- TemplateXamlTreeBuilder.cs
- DateRangeEvent.cs
- SqlDataSourceCustomCommandPanel.cs
- ListSortDescription.cs
- CheckedPointers.cs
- OuterGlowBitmapEffect.cs
- PasswordTextContainer.cs
- DiscoveryServerProtocol.cs
- CanonicalFontFamilyReference.cs
- ParentQuery.cs
- MachineKeySection.cs
- UxThemeWrapper.cs
- Atom10FormatterFactory.cs
- BinaryCommonClasses.cs
- ContourSegment.cs
- InternalSafeNativeMethods.cs
- GPRECTF.cs
- ItemsControlAutomationPeer.cs
- XmlUtf8RawTextWriter.cs
- BindingSource.cs
- ArrayList.cs
- SynchronizingStream.cs
- DataRecordObjectView.cs
- BoolExpression.cs
- WebPartMenuStyle.cs
- XmlTypeAttribute.cs
- _LocalDataStoreMgr.cs
- Comparer.cs
- EncoderFallback.cs
- ClusterSafeNativeMethods.cs
- SystemNetworkInterface.cs
- ImageKeyConverter.cs
- Block.cs
- IpcChannelHelper.cs
- WasHttpHandlersInstallComponent.cs
- BufferModeSettings.cs
- HandlerWithFactory.cs
- PingOptions.cs
- FacetChecker.cs
- KeyProperty.cs
- CompilationUtil.cs
- OleDbException.cs
- SequenceFullException.cs
- WorkflowApplicationException.cs
- CapabilitiesPattern.cs
- NetworkAddressChange.cs
- OracleParameter.cs
- ToolStripMenuItem.cs
- HeaderCollection.cs
- XmlSchemaSimpleTypeList.cs
- TagMapInfo.cs
- ConfigurationSection.cs
- ComboBox.cs
- ColumnWidthChangingEvent.cs
- PathGradientBrush.cs
- WebPartExportVerb.cs
- SiteOfOriginContainer.cs
- Point3DValueSerializer.cs
- AdvancedBindingPropertyDescriptor.cs
- TileBrush.cs
- KeyValueConfigurationCollection.cs
- ReversePositionQuery.cs
- XmlNodeList.cs
- SerialErrors.cs
- DependencyPropertyKey.cs
- TimelineGroup.cs
- FormatterServices.cs
- DataExpression.cs
- DrawingImage.cs
- OdbcErrorCollection.cs
- SkinBuilder.cs
- AggregateNode.cs
- Operators.cs
- LayoutEngine.cs