public void Can_get_and_set_constraint_via_wrapper_property() { var associationType = new AssociationType("A", XmlConstants.ModelNamespace_3, false, DataSpace.CSpace) { SourceEnd = new AssociationEndMember("S", new EntityType("E", "N", DataSpace.CSpace)), TargetEnd = new AssociationEndMember("T", new EntityType("E", "N", DataSpace.CSpace)) }; Assert.Null(associationType.Constraint); Assert.False(associationType.IsForeignKey); var property = EdmProperty.CreatePrimitive("Fk", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); var referentialConstraint = new ReferentialConstraint( associationType.SourceEnd, associationType.TargetEnd, new[] { property }, new[] { property }); associationType.Constraint = referentialConstraint; Assert.Same(referentialConstraint, associationType.Constraint); Assert.True(associationType.IsForeignKey); }
public void Apply_should_set_principal_end_kind_to_required_when_all_properties_not_nullable() { var associationType = new AssociationType("A", XmlConstants.ModelNamespace_3, false, DataSpace.CSpace); associationType.SourceEnd = new AssociationEndMember("S", new EntityType("E", "N", DataSpace.CSpace)); associationType.TargetEnd = new AssociationEndMember("T", new EntityType("E", "N", DataSpace.CSpace)); associationType.SourceEnd.RelationshipMultiplicity = RelationshipMultiplicity.ZeroOrOne; var property1 = EdmProperty.CreatePrimitive("P1", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); var property2 = EdmProperty.CreatePrimitive("P2", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); var associationConstraint = new ReferentialConstraint( associationType.SourceEnd, associationType.TargetEnd, new[] { property1, property2 }, new[] { property1, property2 }); associationConstraint.ToProperties.Each(p => p.Nullable = false); associationType.Constraint = associationConstraint; (new ForeignKeyAssociationMultiplicityConvention()) .Apply(associationType, new DbModel(new EdmModel(DataSpace.CSpace), null)); Assert.True(associationType.SourceEnd.IsRequired()); }
internal ForeignKeyConstraint(RelationshipSet relationshipSet, ReferentialConstraint constraint) { var assocSet = relationshipSet as AssociationSet; var fromEnd = constraint.FromRole as AssociationEndMember; var toEnd = constraint.ToRole as AssociationEndMember; // Currently only Associations are supported if (null == assocSet || null == fromEnd || null == toEnd) { throw new NotSupportedException(); } m_constraint = constraint; var parent = MetadataHelper.GetEntitySetAtEnd(assocSet, fromEnd); // relationshipSet.GetRelationshipEndExtent(constraint.FromRole); var child = MetadataHelper.GetEntitySetAtEnd(assocSet, toEnd); // relationshipSet.GetRelationshipEndExtent(constraint.ToRole); m_extentPair = new ExtentPair(parent, child); m_childKeys = new List<string>(); foreach (var prop in constraint.ToProperties) { m_childKeys.Add(prop.Name); } m_parentKeys = new List<string>(); foreach (var prop in constraint.FromProperties) { m_parentKeys.Add(prop.Name); } PlanCompiler.Assert( (RelationshipMultiplicity.ZeroOrOne == fromEnd.RelationshipMultiplicity || RelationshipMultiplicity.One == fromEnd.RelationshipMultiplicity), "from-end of relationship constraint cannot have multiplicity greater than 1"); }
public void Apply_is_noop_when_existing_constraint() { var associationType = new AssociationType("A", XmlConstants.ModelNamespace_3, false, DataSpace.CSpace); associationType.SourceEnd = new AssociationEndMember("S", new EntityType("E", "N", DataSpace.CSpace)); associationType.TargetEnd = new AssociationEndMember("T", new EntityType("E", "N", DataSpace.CSpace)); var property = EdmProperty.Primitive("Fk", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); var associationConstraint = new ReferentialConstraint( associationType.SourceEnd, associationType.TargetEnd, new[] { property }, new[] { property }); associationType.Constraint = associationConstraint; var navigationProperty = new NavigationProperty("N", TypeUsage.Create(new EntityType("E", "N", DataSpace.CSpace))) { RelationshipType = associationType }; ((IEdmConvention<NavigationProperty>)new ForeignKeyNavigationPropertyAttributeConvention()) .Apply(navigationProperty, new EdmModel(DataSpace.CSpace)); Assert.Same(associationConstraint, navigationProperty.Association.Constraint); }
public void Apply_should_transfer_constraint_and_clr_property_info_annotation() { EdmModel model = new TestModelBuilder() .Entities("S", "T") .Association("S", RelationshipMultiplicity.ZeroOrOne, "T", RelationshipMultiplicity.Many) .Association("T", RelationshipMultiplicity.Many, "S", RelationshipMultiplicity.ZeroOrOne); var association2 = model.AssociationTypes.Last(); var mockPropertyInfo = new MockPropertyInfo(); association2.SourceEnd.SetClrPropertyInfo(mockPropertyInfo); var referentialConstraint = new ReferentialConstraint( association2.SourceEnd, association2.TargetEnd, new[] { new EdmProperty("P") }, new[] { new EdmProperty("D") }); association2.Constraint = referentialConstraint; ((IEdmConvention)new AssociationInverseDiscoveryConvention()).Apply(model); Assert.Equal(1, model.AssociationTypes.Count()); Assert.Equal(1, model.Containers.Single().AssociationSets.Count()); var associationType = model.AssociationTypes.Single(); Assert.NotSame(association2, associationType); Assert.Same(referentialConstraint, associationType.Constraint); Assert.Same(associationType.SourceEnd, referentialConstraint.FromRole); Assert.Same(associationType.TargetEnd, referentialConstraint.ToRole); Assert.Same(mockPropertyInfo.Object, associationType.TargetEnd.GetClrPropertyInfo()); }
public void Create_throws_argument_exception_when_called_with_null_or_empty_arguments() { var source = new EntityType("Source", "Namespace", DataSpace.CSpace); var target = new EntityType("Target", "Namespace", DataSpace.CSpace); var sourceEnd = new AssociationEndMember("SourceEnd", source); var targetEnd = new AssociationEndMember("TargetEnd", target); var constraint = new ReferentialConstraint( sourceEnd, targetEnd, new[] { new EdmProperty("SourceProperty") }, new[] { new EdmProperty("TargetProperty") }); var associationType = AssociationType.Create( "AssociationType", "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, Enumerable.Empty<MetadataProperty>()); var sourceSet = new EntitySet("SourceSet", "Schema", "Table", "Query", source); var targetSet = new EntitySet("TargetSet", "Schema", "Table", "Query", target); var metadataProperty = new MetadataProperty( "MetadataProperty", TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), "value"); // name is null Assert.Throws<ArgumentException>( () => AssociationSet.Create( null, associationType, sourceSet, targetSet, new [] { metadataProperty })); // name is empty Assert.Throws<ArgumentException>( () => AssociationSet.Create( String.Empty, associationType, sourceSet, targetSet, new[] { metadataProperty })); // type is null Assert.Throws<ArgumentNullException>( () => AssociationSet.Create( "AssociationSet", null, sourceSet, targetSet, new[] { metadataProperty })); }
public void Create_throws_argument_exception_when_called_with_null_or_empty_arguments() { var source = new EntityType("Source", "Namespace", DataSpace.CSpace); var target = new EntityType("Target", "Namespace", DataSpace.CSpace); var sourceEnd = new AssociationEndMember("SourceEnd", source); var targetEnd = new AssociationEndMember("TargetEnd", target); var constraint = new ReferentialConstraint( sourceEnd, targetEnd, new[] { new EdmProperty("SourceProperty") }, new[] { new EdmProperty("TargetProperty") }); var associationType = AssociationType.Create( "AssociationType", "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, Enumerable.Empty <MetadataProperty>()); var sourceSet = new EntitySet("SourceSet", "Schema", "Table", "Query", source); var targetSet = new EntitySet("TargetSet", "Schema", "Table", "Query", target); var metadataProperty = new MetadataProperty( "MetadataProperty", TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), "value"); // name is null Assert.Throws <ArgumentException>( () => AssociationSet.Create( null, associationType, sourceSet, targetSet, new [] { metadataProperty })); // name is empty Assert.Throws <ArgumentException>( () => AssociationSet.Create( String.Empty, associationType, sourceSet, targetSet, new[] { metadataProperty })); // type is null Assert.Throws <ArgumentNullException>( () => AssociationSet.Create( "AssociationSet", null, sourceSet, targetSet, new[] { metadataProperty })); }
protected override void VisitEdmAssociationConstraint(ReferentialConstraint item) { _schemaWriter.WriteReferentialConstraintElementHeader(); _schemaWriter.WriteReferentialConstraintRoleElement( XmlConstants.PrincipalRole, item.FromRole, item.FromProperties); _schemaWriter.WriteReferentialConstraintRoleElement( XmlConstants.DependentRole, item.ToRole, item.ToProperties); VisitMetadataItem(item); _schemaWriter.WriteEndElement(); }
public void FromProperties_lazy_loaded_when_none_present() { var principalEntity = new EntityType("E", "N", DataSpace.CSpace); principalEntity.AddKeyMember(new EdmProperty("K")); var referentialConstraint = new ReferentialConstraint( new AssociationEndMember("P", principalEntity), new AssociationEndMember("D", new EntityType("E", "N", DataSpace.CSpace)), Enumerable.Empty<EdmProperty>(), Enumerable.Empty<EdmProperty>()); Assert.NotEmpty(referentialConstraint.FromProperties); }
public void FromProperties_lazy_loaded_when_none_present() { var principalEntity = new EntityType("E", "N", DataSpace.CSpace); principalEntity.AddKeyMember(new EdmProperty("K")); var referentialConstraint = new ReferentialConstraint( new AssociationEndMember("P", principalEntity), new AssociationEndMember("D", new EntityType("E", "N", DataSpace.CSpace)), Enumerable.Empty <EdmProperty>(), Enumerable.Empty <EdmProperty>()); Assert.NotEmpty(referentialConstraint.FromProperties); }
public void Create_sets_properties_and_seals_the_instance() { var source = new EntityType("Source", "Namespace", DataSpace.CSpace); var target = new EntityType("Target", "Namespace", DataSpace.CSpace); var sourceEnd = new AssociationEndMember("SourceEnd", source); var targetEnd = new AssociationEndMember("TargetEnd", target); var constraint = new ReferentialConstraint( sourceEnd, targetEnd, new[] { new EdmProperty("SourceProperty") }, new[] { new EdmProperty("TargetProperty") }); var associationType = AssociationType.Create( "AssociationType", "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, Enumerable.Empty <MetadataProperty>()); var sourceSet = new EntitySet("SourceSet", "Schema", "Table", "Query", source); var targetSet = new EntitySet("TargetSet", "Schema", "Table", "Query", target); var metadataProperty = new MetadataProperty( "MetadataProperty", TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), "value"); var associationSet = AssociationSet.Create( "AssociationSet", associationType, sourceSet, targetSet, new[] { metadataProperty }); Assert.Equal("AssociationSet", associationSet.Name); Assert.Same(associationType, associationSet.ElementType); Assert.Same(sourceSet, associationSet.SourceSet); Assert.Same(targetSet, associationSet.TargetSet); Assert.Same(source, associationSet.SourceEnd.GetEntityType()); Assert.Same(target, associationSet.TargetEnd.GetEntityType()); Assert.Same(metadataProperty, associationSet.MetadataProperties.SingleOrDefault(p => p.Name == "MetadataProperty")); Assert.True(associationSet.IsReadOnly); }
public void Can_set_and_get_dependent_end() { var dependentEnd1 = new AssociationEndMember("D", new EntityType()); var referentialConstraint = new ReferentialConstraint( new AssociationEndMember("P", new EntityType()), dependentEnd1, new[] { EdmProperty.Primitive("P", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)) }, new[] { EdmProperty.Primitive("D", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)) }); Assert.Same(dependentEnd1, referentialConstraint.DependentEnd); var dependentEnd2 = new AssociationEndMember("D2", new EntityType()); referentialConstraint.DependentEnd = dependentEnd2; Assert.Same(dependentEnd2, referentialConstraint.DependentEnd); }
public void Can_set_and_get_to_role() { var toRole = new AssociationEndMember("D", new EntityType("E", "N", DataSpace.CSpace)); var referentialConstraint = new ReferentialConstraint( new AssociationEndMember("P", new EntityType("E", "N", DataSpace.CSpace)), toRole, new[] { EdmProperty.Primitive("P", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)) }, new[] { EdmProperty.Primitive("D", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)) }); Assert.Same(toRole, referentialConstraint.ToRole); var toRole2 = new AssociationEndMember("D2", new EntityType("E", "N", DataSpace.CSpace)); referentialConstraint.ToRole = toRole2; Assert.Same(toRole2, referentialConstraint.ToRole); }
private static AssociationType CreateCSpaceAssociationType(int index) { var sourceProperty = new EdmProperty("SourceProperty"); var targetProperty = new EdmProperty("TargetProperty"); var sourceEntityType = EntityType.Create( "SourceEntityType" + index, "Namespace", DataSpace.CSpace, new [] { "SourceProperty" }, new[] { sourceProperty }, Enumerable.Empty <MetadataProperty>()); var targetEntityType = EntityType.Create( "TargetEntityType" + index, "Namespace", DataSpace.CSpace, new[] { "TargetProperty" }, new[] { targetProperty }, Enumerable.Empty <MetadataProperty>()); var sourceEnd = new AssociationEndMember("SourceEnd" + index, sourceEntityType); var targetEnd = new AssociationEndMember("TargetEnd" + index, targetEntityType); var constraint = new ReferentialConstraint( sourceEnd, targetEnd, new[] { sourceProperty }, new[] { targetProperty }); var associationType = AssociationType.Create( "AssociationType" + index, "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, Enumerable.Empty <MetadataProperty>()); return(associationType); }
public IEnumerable <EdmProperty> GetDependentProperties() { AssociationType relationshipType = (AssociationType)this.RelationshipType; if (relationshipType.ReferentialConstraints.Count > 0) { ReferentialConstraint referentialConstraint = relationshipType.ReferentialConstraints[0]; if (referentialConstraint.ToRole.EdmEquals((MetadataItem)this.FromEndMember)) { ReadOnlyMetadataCollection <EdmMember> keyMembers = referentialConstraint.FromRole.GetEntityType().KeyMembers; List <EdmProperty> edmPropertyList = new List <EdmProperty>(keyMembers.Count); for (int index = 0; index < keyMembers.Count; ++index) { edmPropertyList.Add(referentialConstraint.ToProperties[referentialConstraint.FromProperties.IndexOf((EdmProperty)keyMembers[index])]); } return((IEnumerable <EdmProperty>) new ReadOnlyCollection <EdmProperty>((IList <EdmProperty>)edmPropertyList)); } } return(Enumerable.Empty <EdmProperty>()); }
public void BuildConstraintExceptionMessage_returns_message_for_single_property_constraint() { var principalType = new EntityType("Principal", "N", DataSpace.CSpace); var principalProperty = EdmProperty.CreatePrimitive("P1", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); principalType.AddMember(principalProperty); var dependentType = new EntityType("Dependent", "N", DataSpace.CSpace); var dependentProperty = EdmProperty.CreatePrimitive("D1", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); dependentType.AddMember(dependentProperty); var referentialConstraint = new ReferentialConstraint( new AssociationEndMember("P", principalType), new AssociationEndMember("D", dependentType), new[] { principalProperty }, new[] { dependentProperty }); Assert.Equal( Strings.RelationshipManager_InconsistentReferentialConstraintProperties("Principal.P1", "Dependent.D1"), referentialConstraint.BuildConstraintExceptionMessage()); }
/// <summary> /// Creates a read-only AssociationType instance from the specified parameters. /// </summary> /// <param name="name">The name of the association type.</param> /// <param name="namespaceName">The namespace of the association type.</param> /// <param name="foreignKey">Flag that indicates a foreign key (FK) relationship.</param> /// <param name="dataSpace">The data space for the association type.</param> /// <param name="sourceEnd">The source association end member.</param> /// <param name="targetEnd">The target association end member.</param> /// <param name="constraint">A referential constraint.</param> /// <param name="metadataProperties">Metadata properties to be associated with the instance.</param> /// <returns>The newly created AssociationType instance.</returns> /// <exception cref="System.ArgumentException">The specified name is null or empty.</exception> /// <exception cref="System.ArgumentException">The specified namespace is null or empty.</exception> public static AssociationType Create( string name, string namespaceName, bool foreignKey, DataSpace dataSpace, AssociationEndMember sourceEnd, AssociationEndMember targetEnd, ReferentialConstraint constraint, IEnumerable <MetadataProperty> metadataProperties) { Check.NotEmpty(name, "name"); Check.NotEmpty(namespaceName, "namespaceName"); var instance = new AssociationType(name, namespaceName, foreignKey, dataSpace); if (sourceEnd != null) { instance.SourceEnd = sourceEnd; } if (targetEnd != null) { instance.TargetEnd = targetEnd; } if (constraint != null) { instance.AddReferentialConstraint(constraint); } if (metadataProperties != null) { instance.AddMetadataProperties(metadataProperties); } instance.SetReadOnly(); return(instance); }
public void Apply_should_not_discover_when_existing_constraint() { var associationType = new AssociationType(); associationType.SourceEnd = new AssociationEndMember("S", new EntityType()); associationType.TargetEnd = new AssociationEndMember("T", new EntityType()); var property = EdmProperty.Primitive("Fk", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); var associationConstraint = new ReferentialConstraint( associationType.SourceEnd, associationType.TargetEnd, new[] { property }, new[] { property }); associationType.Constraint = associationConstraint; ((IEdmConvention<AssociationType>)new TypeNameForeignKeyDiscoveryConvention()) .Apply(associationType, new EdmModel().Initialize()); Assert.Same(associationConstraint, associationType.Constraint); }
public void Apply_should_not_discover_when_existing_constraint() { var associationType = new AssociationType("A", XmlConstants.ModelNamespace_3, false, DataSpace.CSpace); associationType.SourceEnd = new AssociationEndMember("S", new EntityType("E", "N", DataSpace.CSpace)); associationType.TargetEnd = new AssociationEndMember("T", new EntityType("E", "N", DataSpace.CSpace)); var property = EdmProperty.CreatePrimitive("Fk", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)); var associationConstraint = new ReferentialConstraint( associationType.SourceEnd, associationType.TargetEnd, new[] { property }, new[] { property }); associationType.Constraint = associationConstraint; (new TypeNameForeignKeyDiscoveryConvention()) .Apply(associationType, new DbModel(new EdmModel(DataSpace.CSpace), null)); Assert.Same(associationConstraint, associationType.Constraint); }
public void Create_sets_properties_and_seals_the_instance() { var source = new EntityType("Source", "Namespace", DataSpace.CSpace); var target = new EntityType("Target", "Namespace", DataSpace.CSpace); var sourceEnd = new AssociationEndMember("SourceEnd", source); var targetEnd = new AssociationEndMember("TargetEnd", target); var constraint = new ReferentialConstraint( sourceEnd, targetEnd, new[] { new EdmProperty("SourceProperty") }, new[] { new EdmProperty("TargetProperty") }); var metadataProperty = new MetadataProperty( "MetadataProperty", TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), "value"); var associationType = AssociationType.Create( "AssociationType", "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, new[] { metadataProperty }); Assert.Equal("Namespace.AssociationType", associationType.FullName); Assert.Equal(true, associationType.IsForeignKey); Assert.Equal(DataSpace.CSpace, associationType.DataSpace); Assert.Same(sourceEnd, associationType.SourceEnd); Assert.Same(targetEnd, associationType.TargetEnd); Assert.Same(constraint, associationType.Constraint); Assert.Same(metadataProperty, associationType.MetadataProperties.SingleOrDefault(p => p.Name == "MetadataProperty")); Assert.True(associationType.IsReadOnly); }
private static DbRelatedEntityRef RelatedEntityRefFromAssociationSetEnd( EntityType constructedEntityType, DbNewInstanceExpression entityConstructor, AssociationSetEnd principalSetEnd, ReferentialConstraint fkConstraint) { var principalEntityType = (EntityType)TypeHelpers.GetEdmType<RefType>(fkConstraint.FromRole.TypeUsage).ElementType; IList<DbExpression> principalKeyValues = null; // Create Entity Property/DbExpression value pairs from the entity constructor DbExpression, // then join these with the principal/dependent property pairs from the FK constraint // to produce principal property name/DbExpression value pairs from which to create the principal ref. // // Ideally the code would be as below, but anonymous types break asmmeta: //var keyPropAndValue = // from pv in constructedEntityType.Properties.Select((p, idx) => new { DependentProperty = p, Value = entityConstructor.Arguments[idx] }) // join ft in fkConstraint.FromProperties.Select((fp, idx) => new { PrincipalProperty = fp, DependentProperty = fkConstraint.ToProperties[idx] }) // on pv.DependentProperty equals ft.DependentProperty // select new { PrincipalProperty = ft.PrincipalProperty.Name, Value = pv.Value }; // var keyPropAndValue = from pv in constructedEntityType.Properties.Select((p, idx) => Tuple.Create(p, entityConstructor.Arguments[idx])) // new { DependentProperty = p, Value = entityConstructor.Arguments[idx] }) join ft in fkConstraint.FromProperties.Select((fp, idx) => Tuple.Create(fp, fkConstraint.ToProperties[idx])) //new { PrincipalProperty = fp, DependentProperty = fkConstraint.ToProperties[idx] }) on pv.Item1 equals ft.Item2 //pv.DependentProperty equals ft.DependentProperty select Tuple.Create(ft.Item1.Name, pv.Item2); // new { PrincipalProperty = ft.PrincipalProperty.Name, Value = pv.Value }; // If there is only a single property in the principal's key, then there is no ordering concern. // Otherwise, create a dictionary of principal key property name to DbExpression value so that // when used as the arguments to the ref expression, the dependent property values - used here // as principal key property values - are in the correct order, which is the same order as the // key members themselves. // if (fkConstraint.FromProperties.Count == 1) { var singleKeyNameAndValue = keyPropAndValue.Single(); Debug.Assert(singleKeyNameAndValue.Item1 == fkConstraint.FromProperties[0].Name, "Unexpected single key property name"); principalKeyValues = new[] { singleKeyNameAndValue.Item2 }; } else { var keyValueMap = keyPropAndValue.ToDictionary(pav => pav.Item1, pav => pav.Item2, StringComparer.Ordinal); principalKeyValues = principalEntityType.KeyMemberNames.Select(memberName => keyValueMap[memberName]).ToList(); } // Create the ref to the principal entity based on the (now correctly ordered) key value expressions. // var principalRef = principalSetEnd.EntitySet.CreateRef(principalEntityType, principalKeyValues); var result = DbExpressionBuilder.CreateRelatedEntityRef(fkConstraint.ToRole, fkConstraint.FromRole, principalRef); return result; }
private static bool IsFKPartiallyContainedInPK( ReferentialConstraint constraint, string associationTypeName, IList<EdmSchemaError> errors) { var toType = (EntityType)constraint.ToProperties[0].DeclaringType; var toPropertiesAreFullyContainedInPK = true; var toPropertiesContainedAtLeastOnePK = false; foreach (var edmProperty in constraint.ToProperties) { // Check if there is at least one to property is not primary key. toPropertiesAreFullyContainedInPK &= toType.KeyMembers.Contains(edmProperty); // Check if there is one to property is primary key. toPropertiesContainedAtLeastOnePK |= toType.KeyMembers.Contains(edmProperty); } if (!toPropertiesAreFullyContainedInPK && toPropertiesContainedAtLeastOnePK) { var foreignKeys = MembersToCommaSeparatedString(constraint.ToProperties); var primaryKeys = MembersToCommaSeparatedString(toType.KeyMembers); errors.Add( new EdmSchemaError( string.Format( CultureInfo.InvariantCulture, Resources_VersioningFacade.UnsupportedForeignKeyPattern, associationTypeName, foreignKeys, primaryKeys, toType.Name), (int)ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Warning)); return true; } return false; }
private static bool AreAllEntityColumnsMappedAsToColumns( EntitySet storeEntitySet, ReferentialConstraint constraint0, ReferentialConstraint constraint1) { var names = new HashSet<string>(constraint0.ToProperties.Select(p => p.Name)); names.UnionWith(constraint1.ToProperties.Select(p => p.Name)); return names.Count == storeEntitySet.ElementType.Properties.Count; }
protected override void VisitEdmAssociationConstraint(ReferentialConstraint item) { _schemaWriter.WriteReferentialConstraintElementHeader(); _schemaWriter.WriteReferentialConstraintRoleElement( XmlConstants.PrincipalRole, item.PrincipalEnd(_currentAssociationType), item.PrincipalEnd(_currentAssociationType).GetEntityType().GetValidKey()); _schemaWriter.WriteReferentialConstraintRoleElement( XmlConstants.DependentRole, item.DependentEnd, item.ToProperties); VisitMetadataItem(item); _schemaWriter.WriteEndElement(); }
// Check if related entities contain proper property values internal override bool CheckReferentialConstraintPrincipalProperty(EntityEntry ownerEntry, ReferentialConstraint constraint) { EntityKey principalKey; if (!IsEmpty()) { var wrappedRelatedEntity = ReferenceValue; // For Added entities, it doesn't matter what the key value is since it can't be trusted anyway. if (wrappedRelatedEntity.ObjectStateEntry != null && wrappedRelatedEntity.ObjectStateEntry.State == EntityState.Added) { return true; } principalKey = ExtractPrincipalKey(wrappedRelatedEntity); } else if ((ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne || ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) && DetachedEntityKey != null) { // Generally for foreign keys we want to use the EntityKey to do RI constraint validation // However, if we are doing an Add/Attach, we should use the DetachedEntityKey because this is the value // set by the user while the entity was detached, and should be used until the entity is fully added/attached if (IsForeignKey && !(ObjectContext.ObjectStateManager.TransactionManager.IsAddTracking || ObjectContext.ObjectStateManager.TransactionManager.IsAttachTracking)) { principalKey = EntityKey; } else { principalKey = DetachedEntityKey; } } else { // We only need to check for RI constraints if the related end contains a real entity or is a reference with a detached entitykey return true; } return VerifyRIConstraintsWithRelatedEntry(constraint, ownerEntry.GetCurrentEntityValue, principalKey); }
internal override bool CheckReferentialConstraintDependentProperty(EntityEntry ownerEntry, ReferentialConstraint constraint) { // if the related end contains a real entity or is a reference with a detached entitykey, we need to check for RI constraints if (!IsEmpty()) { return base.CheckReferentialConstraintDependentProperty(ownerEntry, constraint); } else if ((ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne || ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) && DetachedEntityKey != null) { // related end is empty, so we must have a reference with a detached key var detachedKey = DetachedEntityKey; #if DEBUG // If the constraint is not PK<->PK then we can't validate it here. // This debug code checks that we don't try to validate it. var keyNames = new List<string>( from v in detachedKey.EntityKeyValues select v.Key); foreach (var prop in constraint.ToProperties) { Debug.Assert( keyNames.Contains(prop.Name), "Attempt to validate constraint where some FK values are not in the dependent PK"); } #endif // don't need to validate the principal/detached key here because that has already been done during AttachContext if (!VerifyRIConstraintsWithRelatedEntry(constraint, detachedKey.FindValueByName, ownerEntry.EntityKey)) { return false; } } return true; }
private static AssociationType ConvertToAssociationType( Relationship element, DbProviderManifest providerManifest, Converter.ConversionCache convertedItemCache, Dictionary <SchemaElement, GlobalItem> newGlobalItems) { AssociationType associationType = new AssociationType(element.Name, element.Namespace, element.IsForeignKey, Converter.GetDataSpace(providerManifest)); newGlobalItems.Add((SchemaElement)element, (GlobalItem)associationType); foreach (RelationshipEnd end in (IEnumerable <IRelationshipEnd>)element.Ends) { EntityType endMemberType = (EntityType)Converter.LoadSchemaElement((System.Data.Entity.Core.SchemaObjectModel.SchemaType)end.Type, providerManifest, convertedItemCache, newGlobalItems); AssociationEndMember associationEndMember = Converter.InitializeAssociationEndMember(associationType, (IRelationshipEnd)end, endMemberType); Converter.AddOtherContent((SchemaElement)end, (MetadataItem)associationEndMember); foreach (OnOperation operation in (IEnumerable <OnOperation>)end.Operations) { if (operation.Operation == Operation.Delete) { OperationAction operationAction = OperationAction.None; switch (operation.Action) { case System.Data.Entity.Core.SchemaObjectModel.Action.None: operationAction = OperationAction.None; break; case System.Data.Entity.Core.SchemaObjectModel.Action.Cascade: operationAction = OperationAction.Cascade; break; } associationEndMember.DeleteBehavior = operationAction; } } if (end.Documentation != null) { associationEndMember.Documentation = Converter.ConvertToDocumentation(end.Documentation); } } for (int index = 0; index < element.Constraints.Count; ++index) { System.Data.Entity.Core.SchemaObjectModel.ReferentialConstraint constraint = element.Constraints[index]; AssociationEndMember member1 = (AssociationEndMember)associationType.Members[constraint.PrincipalRole.Name]; AssociationEndMember member2 = (AssociationEndMember)associationType.Members[constraint.DependentRole.Name]; EntityTypeBase elementType1 = ((RefType)member1.TypeUsage.EdmType).ElementType; EntityTypeBase elementType2 = ((RefType)member2.TypeUsage.EdmType).ElementType; ReferentialConstraint referentialConstraint = new ReferentialConstraint((RelationshipEndMember)member1, (RelationshipEndMember)member2, (IEnumerable <EdmProperty>)Converter.GetProperties(elementType1, constraint.PrincipalRole.RoleProperties), (IEnumerable <EdmProperty>)Converter.GetProperties(elementType2, constraint.DependentRole.RoleProperties)); if (constraint.Documentation != null) { referentialConstraint.Documentation = Converter.ConvertToDocumentation(constraint.Documentation); } if (constraint.PrincipalRole.Documentation != null) { referentialConstraint.FromRole.Documentation = Converter.ConvertToDocumentation(constraint.PrincipalRole.Documentation); } if (constraint.DependentRole.Documentation != null) { referentialConstraint.ToRole.Documentation = Converter.ConvertToDocumentation(constraint.DependentRole.Documentation); } associationType.AddReferentialConstraint(referentialConstraint); Converter.AddOtherContent((SchemaElement)element.Constraints[index], (MetadataItem)referentialConstraint); } if (element.Documentation != null) { associationType.Documentation = Converter.ConvertToDocumentation(element.Documentation); } Converter.AddOtherContent((SchemaElement)element, (MetadataItem)associationType); return(associationType); }
private static bool IsAtLeastOneColumnFkInBothAssociations( ReferentialConstraint constraint0, ReferentialConstraint constraint1) { return constraint1.ToProperties.Any(p => constraint0.ToProperties.Contains(p)); }
public void Create_throws_argument_exception_when_called_with_invalid_arguments() { var source = new EntityType("Source", "Namespace", DataSpace.CSpace); var target = new EntityType("Target", "Namespace", DataSpace.CSpace); var sourceEnd = new AssociationEndMember("SourceEnd", source); var targetEnd = new AssociationEndMember("TargetEnd", target); var constraint = new ReferentialConstraint( sourceEnd, targetEnd, new[] { new EdmProperty("SourceProperty") }, new[] { new EdmProperty("TargetProperty") }); var metadataProperty = new MetadataProperty( "MetadataProperty", TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), "value"); Assert.Throws <ArgumentException>( () => AssociationType.Create( null, "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, new[] { metadataProperty })); Assert.Throws <ArgumentException>( () => AssociationType.Create( String.Empty, "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, new[] { metadataProperty })); Assert.Throws <ArgumentException>( () => AssociationType.Create( "AssociationType", null, true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, new[] { metadataProperty })); Assert.Throws <ArgumentException>( () => AssociationType.Create( "AssociationType", String.Empty, true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, new[] { metadataProperty })); }
private static bool IsAtLeastOneColumnOfBothDependentRelationshipColumnSetsNonNullable( ReferentialConstraint constraint0, ReferentialConstraint constraint1) { return constraint0.ToProperties.Any(p => !p.Nullable) && constraint1.ToProperties.Any(p => !p.Nullable); }
private static bool ValidateReferentialConstraint( ReferentialConstraint constraint, bool generateForeignKeyProperties, string associationTypeName, IEnumerable<AssociationType> associationTypes, IList<EdmSchemaError> errors) { if (constraint == null) { return false; } // We can skip validation checks if the FKs are directly surfaced (since we can produce valid mappings in these cases). if (generateForeignKeyProperties) { return true; } if (IsFKPartiallyContainedInPK(constraint, associationTypeName, errors)) { return false; } // Check if any FK (which could also be a PK) is shared among multiple Associations (ie shared via foreign key constraint). // To do this we check if the AssociationType being generated has any dependent property which is also a dependent in one // of the association typed already added. If so, we keep one association and throw the rest away. foreach (var toPropertyOfAddedAssociation in associationTypes.SelectMany( t => t.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties))) { foreach (var toProperty in constraint.ToProperties) { if (toProperty.DeclaringType.Equals(toPropertyOfAddedAssociation.DeclaringType) && toProperty.Equals(toPropertyOfAddedAssociation)) { errors.Add( new EdmSchemaError( string.Format( CultureInfo.InvariantCulture, Resources_VersioningFacade.SharedForeignKey, associationTypeName, toProperty, toProperty.DeclaringType), (int)ModelBuilderErrorCode.SharedForeignKey, EdmSchemaErrorSeverity.Warning)); return false; } } } return true; }
protected override void Visit(ReferentialConstraint referentialConstraint) { int index; if (!AddObjectToSeenListAndHashBuilder(referentialConstraint, out index)) { return; } AddObjectStartDumpToHashBuilder(referentialConstraint, index); #region Inner data visit AddObjectContentToHashBuilder(referentialConstraint.Identity); base.Visit(referentialConstraint); #endregion AddObjectEndDumpToHashBuilder(); }
internal override void Configure( AssociationType associationType, AssociationEndMember dependentEnd, EntityTypeConfiguration entityTypeConfiguration) { DebugCheck.NotNull(associationType); DebugCheck.NotNull(dependentEnd); DebugCheck.NotNull(entityTypeConfiguration); if (!_dependentProperties.Any()) { return; } var dependentPropertInfos = _dependentProperties.AsEnumerable(); if (!IsFullySpecified) { var foreignKeys = from p in _dependentProperties select new { PropertyInfo = p, entityTypeConfiguration.Property(new PropertyPath(p)).ColumnOrder }; if ((_dependentProperties.Count > 1) && foreignKeys.Any(p => !p.ColumnOrder.HasValue)) { var dependentKeys = dependentEnd.GetEntityType().KeyProperties; if ((dependentKeys.Count == _dependentProperties.Count) && foreignKeys.All(fk => dependentKeys.Any(p => p.GetClrPropertyInfo().IsSameAs(fk.PropertyInfo)))) { // The FK and PK sets are equal, we know the order dependentPropertInfos = dependentKeys.Select(p => p.GetClrPropertyInfo()); } else { throw Error.ForeignKeyAttributeConvention_OrderRequired(entityTypeConfiguration.ClrType); } } else { dependentPropertInfos = foreignKeys.OrderBy(p => p.ColumnOrder).Select(p => p.PropertyInfo); } } var dependentProperties = new List<EdmProperty>(); foreach (var dependentProperty in dependentPropertInfos) { var property = dependentEnd.GetEntityType() .GetDeclaredPrimitiveProperty(dependentProperty); if (property == null) { throw Error.ForeignKeyPropertyNotFound( dependentProperty.Name, dependentEnd.GetEntityType().Name); } dependentProperties.Add(property); } var principalEnd = associationType.GetOtherEnd(dependentEnd); var associationConstraint = new ReferentialConstraint( principalEnd, dependentEnd, principalEnd.GetEntityType().KeyProperties, dependentProperties); if (principalEnd.IsRequired()) { associationConstraint.ToProperties.Each(p => p.Nullable = false); } associationType.Constraint = associationConstraint; }
/// <summary> /// Add the given referential constraint to the collection of referential constraints /// </summary> internal void AddReferentialConstraint(ReferentialConstraint referentialConstraint) { ReferentialConstraints.Source.Add(referentialConstraint); }
// <summary> // Add the given referential constraint to the collection of referential constraints // </summary> internal void AddReferentialConstraint(ReferentialConstraint referentialConstraint) { ReferentialConstraints.Source.Add(referentialConstraint); }
protected virtual void Visit(ReferentialConstraint referentialConstraint) { foreach (var property in referentialConstraint.FromProperties) { Visit(property); } Visit(referentialConstraint.FromRole); foreach (var property in referentialConstraint.ToProperties) { Visit(property); } Visit(referentialConstraint.ToRole); }
/// <summary> /// Creates an EntityKey for a principal entity based on the foreign key values contained /// in this entity. This implies that this entity is at the dependent end of the relationship. /// </summary> /// <param name="dependentEntry"> The EntityEntry for the dependent that contains the FK </param> /// <param name="constraint"> The constraint that describes this FK relationship </param> /// <param name="principalEntitySet"> The entity set at the principal end of the the relationship </param> /// <param name="useOriginalValues"> If true then the key will be constructed from the original FK values </param> /// <returns> The key, or null if any value in the key is null </returns> public static EntityKey CreateKeyFromForeignKeyValues( EntityEntry dependentEntry, ReferentialConstraint constraint, EntitySet principalEntitySet, bool useOriginalValues) { // Build the key values. If any part of the key is null, then the entire key // is considered null. var dependentProps = constraint.ToProperties; var numValues = dependentProps.Count; if (numValues == 1) { var keyValue = useOriginalValues ? dependentEntry.GetOriginalEntityValue(dependentProps.First().Name) : dependentEntry.GetCurrentEntityValue(dependentProps.First().Name); return keyValue == DBNull.Value ? null : new EntityKey(principalEntitySet, keyValue); } // Note that the properties in the principal entity set may be in a different order than // they appear in the constraint. Therefore, we create name value mappings to ensure that // the correct values are associated with the correct properties. // Unfortunately, there is not way to call the public EntityKey constructor that takes pairs // because the internal "object" constructor hides it. Even this doesn't work: // new EntityKey(principalEntitySet, (IEnumerable<KeyValuePair<string, object>>)keyValues) var keyNames = principalEntitySet.ElementType.KeyMemberNames; Debug.Assert(keyNames.Length == numValues, "Number of entity set key names does not match constraint names"); var values = new object[numValues]; var principalProps = constraint.FromProperties; for (var i = 0; i < numValues; i++) { var value = useOriginalValues ? dependentEntry.GetOriginalEntityValue(dependentProps[i].Name) : dependentEntry.GetCurrentEntityValue(dependentProps[i].Name); if (value == DBNull.Value) { return null; } var keyIndex = Array.IndexOf(keyNames, principalProps[i].Name); Debug.Assert(keyIndex >= 0 && keyIndex < numValues, "Could not find constraint prop name in entity set key names"); values[keyIndex] = value; } return new EntityKey(principalEntitySet, values); }
private static bool IsEntityDependentSideOfBothAssociations( EntitySet storeEntitySet, ReferentialConstraint constraint0, ReferentialConstraint constraint1) { return ((RefType)constraint0.ToRole.TypeUsage.EdmType).ElementType == storeEntitySet.ElementType && ((RefType)constraint1.ToRole.TypeUsage.EdmType).ElementType == storeEntitySet.ElementType; }
/// <summary> /// If this is a property that participates in the principal end of a referential constraint, this method will return /// the corresponding property on the dependent end. /// </summary> /// <example> /// <ReferentialConstraint> /// <Principal Role="DiscontinuedProduct"> /// <PropertyRef Name="ProductId" /> /// <PropertyRef Name="ProductName" /> /// </Principal> /// <Dependent Role="DiscontinuedItem"> /// <PropertyRef Name="ItemId" /> /// <PropertyRef Name="ItemName" /> /// </Dependent> /// </ReferentialConstraint> /// In this example, if 'ProductName' were passed into this method, 'ItemName' would be returned. /// </example> /// <param name="property">The property on the principal end of the referential constraint</param> /// <param name="refConstraint">The referential constraint.</param> /// <returns>The property on the dependent end of the referentail constraint corresponding to the property on the principal end</returns> /// <exception cref="ArgumentNullException">if the ref constraint is null</exception> /// <exception cref="InvalidOperationException">if the property cannot be found among the properties on the principal end of the referential constraint</exception> public static EdmProperty GetDependentProperty(this EdmProperty property, ReferentialConstraint refConstraint) { if (refConstraint == null) { throw new ArgumentNullException("refConstraint"); } var indexInFromProperties = refConstraint.FromProperties.IndexOf(property); if (indexInFromProperties == -1) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, Resources.ErrorNoPropertyInRefConstraint, property.Name, refConstraint.FromRole.Name, refConstraint.ToRole.Name)); } return refConstraint.ToProperties.ElementAt(indexInFromProperties); }
/// <summary> /// Creates a read-only AssociationType instance from the specified parameters. /// </summary> /// <param name="name">The name of the association type.</param> /// <param name="namespaceName">The namespace of the association type.</param> /// <param name="foreignKey">Flag that indicates a foreign key (FK) relationship.</param> /// <param name="dataSpace">The data space for the association type.</param> /// <param name="sourceEnd">The source association end member.</param> /// <param name="targetEnd">The target association end member.</param> /// <param name="constraint">A referential constraint.</param> /// <param name="metadataProperties">Metadata properties to be associated with the instance.</param> /// <returns>The newly created AssociationType instance.</returns> /// <exception cref="System.ArgumentException">The specified name is null or empty.</exception> /// <exception cref="System.ArgumentException">The specified namespace is null or empty.</exception> public static AssociationType Create( string name, string namespaceName, bool foreignKey, DataSpace dataSpace, AssociationEndMember sourceEnd, AssociationEndMember targetEnd, ReferentialConstraint constraint, IEnumerable<MetadataProperty> metadataProperties) { Check.NotEmpty(name, "name"); Check.NotEmpty(namespaceName, "namespaceName"); var instance = new AssociationType(name, namespaceName, foreignKey, dataSpace); if (sourceEnd != null) { instance.SourceEnd = sourceEnd; } if (targetEnd != null) { instance.TargetEnd = targetEnd; } if (constraint != null) { instance.AddReferentialConstraint(constraint); } if (metadataProperties != null) { instance.AddMetadataProperties(metadataProperties.ToList()); } instance.SetReadOnly(); return instance; }
public void Create_sets_properties_and_seals_the_instance() { var source = new EntityType("Source", "Namespace", DataSpace.CSpace); var target = new EntityType("Target", "Namespace", DataSpace.CSpace); var sourceEnd = new AssociationEndMember("SourceEnd", source); var targetEnd = new AssociationEndMember("TargetEnd", target); var constraint = new ReferentialConstraint( sourceEnd, targetEnd, new[] { new EdmProperty("SourceProperty") }, new[] { new EdmProperty("TargetProperty") }); var associationType = AssociationType.Create( "AssociationType", "Namespace", true, DataSpace.CSpace, sourceEnd, targetEnd, constraint, Enumerable.Empty<MetadataProperty>()); var sourceSet = new EntitySet("SourceSet", "Schema", "Table", "Query", source); var targetSet = new EntitySet("TargetSet", "Schema", "Table", "Query", target); var metadataProperty = new MetadataProperty( "MetadataProperty", TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String)), "value"); var associationSet = AssociationSet.Create( "AssociationSet", associationType, sourceSet, targetSet, new[] { metadataProperty }); Assert.Equal("AssociationSet", associationSet.Name); Assert.Same(associationType, associationSet.ElementType); Assert.Same(sourceSet, associationSet.SourceSet); Assert.Same(targetSet, associationSet.TargetSet); Assert.Same(source, associationSet.SourceEnd.GetEntityType()); Assert.Same(target, associationSet.TargetEnd.GetEntityType()); Assert.Same(metadataProperty, associationSet.MetadataProperties.SingleOrDefault(p => p.Name == "MetadataProperty")); Assert.True(associationSet.IsReadOnly); }