-
Notifications
You must be signed in to change notification settings - Fork 351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nullable attribute missing for collection type reference #2034
base: release-7.x
Are you sure you want to change the base?
Changes from all commits
94de6d3
0fda561
74b4a94
8be4c66
23de419
3d02769
2ae59f6
baa96d6
93d30f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -311,7 +311,8 @@ public void WriteNavigationPropertyInComplexType() | |
}, | ||
""Addresses"": { | ||
""$Collection"": true, | ||
""$Type"": ""DefaultNs.Address"" | ||
""$Type"": ""DefaultNs.Address"", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nullable facet is required for collections in XML, but I don't think it's required in JSON. Which means our factoring is a bit off -- we shouldn't have code in the serializer to determine whether the null needs to be written. Instead, we should pass down the information that lets the XML serializer decide whether or not to write the null value (i.e., whether or not we are writing a structural property). |
||
""$Nullable"": false | ||
} | ||
}, | ||
""City"": { | ||
|
@@ -745,7 +746,7 @@ public void SetNavigationPropertyPartnerTest() | |
}, | ||
""ComplexProp"": { | ||
""$Collection"": true, | ||
""$Type"": ""NS.ComplexType1"" | ||
""$Type"": ""NS.ComplexType1"", | ||
}, | ||
""OuterNavA"": { | ||
""$Kind"": ""NavigationProperty"", | ||
|
@@ -1421,7 +1422,7 @@ public void ShouldWriteEdmPathTypeProperty() | |
"<edmx:DataServices>" + | ||
"<Schema Namespace=\"NS\" xmlns=\"http://docs.oasis-open.org/odata/ns/edm\">" + | ||
"<ComplexType Name=\"SelectType\">" + | ||
"<Property Name=\"DefaultSelect\" Type=\"Collection(Edm.PropertyPath)\" />" + | ||
"<Property Name=\"DefaultSelect\" Type=\"Collection(Edm.PropertyPath)\" Nullable=\"true\" />" + | ||
"<Property Name=\"DefaultHidden\" Type=\"Collection(Edm.NavigationPropertyPath)\" Nullable=\"false\" />" + | ||
"</ComplexType>" + | ||
"<Term Name=\"MyTerm\" Type=\"NS.SelectType\" />" + | ||
|
@@ -1442,7 +1443,8 @@ public void ShouldWriteEdmPathTypeProperty() | |
}, | ||
""DefaultHidden"": { | ||
""$Collection"": true, | ||
""$Type"": ""Edm.NavigationPropertyPath"" | ||
""$Type"": ""Edm.NavigationPropertyPath"", | ||
""$Nullable"": false | ||
} | ||
}, | ||
""MyTerm"": { | ||
|
@@ -1604,8 +1606,8 @@ public void CanWriteEdmEntityTypeWithCollectionAbstractTypeButValidationFailed() | |
"<PropertyRef Name=\"Id\" />" + | ||
"</Key>" + | ||
"<Property Name=\"Id\" Type=\"Edm.Int32\" Nullable=\"false\" />" + | ||
"<Property Name=\"Primitive\" Type=\"Collection(Edm.PrimitiveType)\" />" + | ||
"<Property Name=\"Complex\" Type=\"Collection(Edm.ComplexType)\" />" + | ||
"<Property Name=\"Primitive\" Type=\"Collection(Edm.PrimitiveType)\" Nullable=\"true\" />" + | ||
"<Property Name=\"Complex\" Type=\"Collection(Edm.ComplexType)\" Nullable=\"true\" />" + | ||
"</EntityType>" + | ||
"</Schema>" + | ||
"</edmx:DataServices>" + | ||
|
@@ -2377,7 +2379,7 @@ public void CanWriteEdmModelWithUntypedProperty() | |
"</Key>" + | ||
"<Property Name=\"Id\" Type=\"Edm.String\" />" + | ||
"<Property Name=\"Value\" Type=\"Edm.Untyped\" />" + | ||
"<Property Name=\"Data\" Type=\"Collection(Edm.Untyped)\" />" + | ||
"<Property Name=\"Data\" Type=\"Collection(Edm.Untyped)\" Nullable=\"true\" />" + | ||
"</EntityType>" + | ||
"</Schema>" + | ||
"</edmx:DataServices>" + | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,7 +93,7 @@ public void VerifyComplexTypeWithNavigationPropertiesWrittenCorrectly() | |
// Act & Assert for XML | ||
VisitAndVerifyXml(v => v.VisitSchemaType(complexType), | ||
@"<ComplexType Name=""Address""> | ||
<Property Name=""Street"" Type=""Collection(Edm.String)"" MaxLength=""42"" Unicode=""false"" /> | ||
<Property Name=""Street"" Type=""Collection(Edm.String)"" Nullable=""true"" MaxLength=""42"" Unicode=""false"" /> | ||
<NavigationProperty Name=""City"" Type=""NS.City"" Nullable=""false"" ContainsTarget=""true""> | ||
<OnDelete Action=""Cascade"" /> | ||
</NavigationProperty> | ||
|
@@ -216,7 +216,8 @@ public void VerifyEntityTypeWithNavigationPropertiesWrittenCorrectly() | |
""$Kind"": ""EntityType"", | ||
""Locations"": { | ||
""$Collection"": true, | ||
""$Type"": ""NS.Address"" | ||
""$Type"": ""NS.Address"", | ||
""$Nullable"": false | ||
}, | ||
""Orders"": { | ||
""$Kind"": ""NavigationProperty"", | ||
|
@@ -2015,6 +2016,53 @@ public void VerifyAnnotationWithRecordExpressionWrittenCorrectly() | |
} | ||
#endregion | ||
|
||
#region Collection Type References | ||
[Fact] | ||
public void VerifyCollectionTypeReferencesWrittenCorrectly() | ||
{ | ||
// see https://github.com/OData/odata.net/issues/2028 | ||
// Arrange | ||
EdmComplexType structuredType = new EdmComplexType("NS", "Customer"); | ||
structuredType.AddStructuralProperty("test01", EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetDecimal(true))); | ||
structuredType.AddStructuralProperty("test02", EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetDecimal(false))); | ||
structuredType.AddStructuralProperty("test03", EdmCoreModel.Instance.GetDecimal(true)); | ||
structuredType.AddStructuralProperty("test04", EdmCoreModel.Instance.GetDecimal(false)); | ||
|
||
// Act & Assert for XML | ||
VisitAndVerifyXml(v => v.VisitSchemaType(structuredType), @"<ComplexType Name=""Customer""> | ||
<Property Name=""test01"" Type=""Collection(Edm.Decimal)"" Nullable=""true"" /> | ||
<Property Name=""test02"" Type=""Collection(Edm.Decimal)"" Nullable=""false"" /> | ||
<Property Name=""test03"" Type=""Edm.Decimal"" /> | ||
<Property Name=""test04"" Type=""Edm.Decimal"" Nullable=""false"" /> | ||
</ComplexType>" | ||
); | ||
|
||
// Act & Assert for JSON | ||
VisitAndVerifyJson(v => v.VisitSchemaType(structuredType), @"{ | ||
""Customer"": { | ||
""$Kind"": ""ComplexType"", | ||
""test01"": { | ||
""$Collection"": true, | ||
""$Type"": ""Edm.Decimal"", | ||
""$Nullable"": true | ||
}, | ||
""test02"": { | ||
""$Collection"": true, | ||
""$Type"": ""Edm.Decimal"", | ||
""$Nullable"": false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't be written in this case for json csdl, right? |
||
}, | ||
""test03"": { | ||
""$Type"": ""Edm.Decimal"", | ||
""$Nullable"": true | ||
}, | ||
""test04"": { | ||
""$Type"": ""Edm.Decimal"" | ||
} | ||
} | ||
}"); | ||
} | ||
#endregion | ||
|
||
internal void VisitAndVerifyXml(Action<EdmModelCsdlSerializationVisitor> testAction, string expected, bool indent = true) | ||
{ | ||
XmlWriter xmlWriter; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this gets set true for structural property facets, and false otherwise? Can we just call this something like "isStructuralPropertyDeclaration"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the call "chain" is
EdmModelCsdlSerializationVisitor.{ProcessStructuralProperty|ProcessTerm|ProcessCollectionType|...)
EdmModelCsdlSerializationVisitor.ProcessFacets ->
EdmModelCsdlSchemaWriter.WriteNullableAttribute
and EdmModelCsdlSchemaWriter is abstract (one concrete subclass for XML, one for JSON)
And yes, it is true that only ProcessStructuralProperty is passing in true. But that doesn't describe the behavior of ProcessFacets which is : instruct the writer to write the property for a collection type (-reference) even if it is false (which otherwise dosn't get written). The name is based on what the method does, not on how and when it is called.
But I don't have a strong opinion. Happy to change it if you prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's discuss -- my concern is that, as I understand it, a component that should be format-agnostic (EdmModelCsdlSerializationVistor) would be making the decision of whether to write the nullable attribute or not based on the format (write for xml, not for json). ideally, we wouldn't be making format-specific decisions in these common classes, they would all be made in the format-specific implementations.