Skip to content

Commit 19522b4

Browse files
committed
[Codeplex issue #2027] [Required] attribute doesn't work on a property of
Complex type. Actually, all property conventions should be re-applyed to the new property if the entity type reconfiged to complex type.
1 parent 27e6385 commit 19522b4

File tree

4 files changed

+113
-0
lines changed

4 files changed

+113
-0
lines changed

OData/src/System.Web.OData/OData/Builder/ODataConventionModelBuilder.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,14 @@ private void ReconfigureEntityTypesAsComplexType(EntityTypeConfiguration[] misco
423423
propertyConfiguration = entityToBePatched.AddComplexProperty(propertyToBeRemoved.PropertyInfo);
424424
}
425425

426+
Contract.Assert(propertyToBeRemoved.AddedExplicitly == false);
427+
428+
// The newly added property must be marked as added implicitly. This can make sure the property
429+
// conventions can be re-applied to the new property.
430+
propertyConfiguration.AddedExplicitly = false;
431+
432+
ReapplyPropertyConvention(propertyConfiguration, entityToBePatched);
433+
426434
propertyConfiguration.Name = propertyNameAlias;
427435
}
428436
}
@@ -815,6 +823,15 @@ private void ApplyPropertyConvention(IEdmPropertyConvention propertyConvention,
815823
}
816824
}
817825

826+
private void ReapplyPropertyConvention(PropertyConfiguration property,
827+
StructuralTypeConfiguration edmTypeConfiguration)
828+
{
829+
foreach (IEdmPropertyConvention propertyConvention in _conventions.OfType<IEdmPropertyConvention>())
830+
{
831+
propertyConvention.Apply(property, edmTypeConfiguration, this);
832+
}
833+
}
834+
818835
private static Dictionary<Type, List<Type>> BuildDerivedTypesMapping(IAssembliesResolver assemblyResolver)
819836
{
820837
IEnumerable<Type> allTypes = TypeHelper.GetLoadedTypes(assemblyResolver).Where(t => t.IsVisible && t.IsClass && t != typeof(object));

OData/test/System.Web.OData.Test/OData/Builder/Conventions/ODataConventionModelBuilderTests.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,40 @@ public void ODataConventionModelBuilder_MappedDerivedTypeHasNoAliasedBasePropert
16081608
Assert.Equal("Heads", property.Name);
16091609
}
16101610

1611+
[Fact]
1612+
public void ODataConventionModelBuilder_RequiredAttribute_WorksOnComplexTypeProperty()
1613+
{
1614+
// Arrange
1615+
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
1616+
builder.EntitySet<RequiredEmployee>("Employees");
1617+
1618+
// Act
1619+
IEdmModel model = builder.GetEdmModel();
1620+
1621+
// Assert
1622+
IEdmEntityType entityType = model.AssertHasEntityType(typeof(RequiredEmployee));
1623+
IEdmProperty property = Assert.Single(entityType.DeclaredProperties.Where(e => e.Name == "Address"));
1624+
Assert.False(property.Type.IsNullable);
1625+
}
1626+
1627+
[Fact]
1628+
public void ODataConventionModelBuilder_QueryLimitAttributes_WorksOnComplexTypeProperty()
1629+
{
1630+
// Arrange
1631+
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
1632+
builder.EntitySet<QueryLimitEmployee>("Employees");
1633+
1634+
// Act
1635+
IEdmModel model = builder.GetEdmModel();
1636+
1637+
// Assert
1638+
IEdmEntityType entityType = model.AssertHasEntityType(typeof(QueryLimitEmployee));
1639+
IEdmProperty property = Assert.Single(entityType.DeclaredProperties.Where(e => e.Name == "Address"));
1640+
1641+
Assert.True(EdmLibHelpers.IsNonFilterable(property, model));
1642+
Assert.True(EdmLibHelpers.IsUnsortable(property, model));
1643+
}
1644+
16111645
[Fact]
16121646
public void ODataConventionModelBuilder_GetEdmModel_ThrowsException_IfHasDateTimeProperty()
16131647
{
@@ -1903,6 +1937,28 @@ public class DerivedManager : BaseEmployee
19031937
public int Heads { get; set; }
19041938
}
19051939

1940+
public class RequiredEmployee
1941+
{
1942+
public int Id { get; set; }
1943+
1944+
[Required]
1945+
public EmployeeAddress Address { get; set; }
1946+
}
1947+
1948+
public class QueryLimitEmployee
1949+
{
1950+
public int Id { get; set; }
1951+
1952+
[NonFilterable]
1953+
[Unsortable]
1954+
public EmployeeAddress Address { get; set; }
1955+
}
1956+
1957+
public class EmployeeAddress
1958+
{
1959+
public string City { get; set; }
1960+
}
1961+
19061962
public enum Gender
19071963
{
19081964
Male = 1,

OData/test/System.Web.OData.Test/OData/Formatter/ODataTestUtil.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,4 +189,18 @@ public class FormatterAddress
189189
public string City { get; set; }
190190
public IDictionary<string, object> Properties { get; set; }
191191
}
192+
193+
public class FormatterAccount
194+
{
195+
public int Id { get; set; }
196+
197+
[Required]
198+
public string Name { get; set; }
199+
200+
[Required]
201+
public FormatterAddress Address { get; set; }
202+
203+
[Required]
204+
public IList<FormatterAddress> Addresses { get; set; }
205+
}
192206
}

OData/test/System.Web.OData.Test/OData/MetadataControllerTest.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,32 @@ public void Controller_DoesNotAppear_InApiDescriptions()
292292
Assert.DoesNotContain("ODataMetadata", apis);
293293
}
294294

295+
[Fact]
296+
public void RequiredAttribute_Works_OnComplexTypeProperty()
297+
{
298+
// Arrange
299+
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
300+
builder.EntitySet<FormatterAccount>("Accounts");
301+
302+
var config = new[] { typeof(MetadataController) }.GetHttpConfiguration();
303+
config.MapODataServiceRoute(builder.GetEdmModel());
304+
305+
HttpServer server = new HttpServer(config);
306+
HttpClient client = new HttpClient(server);
307+
308+
// Act
309+
var responseString = client.GetStringAsync("http://localhost/$metadata").Result;
310+
311+
// Assert
312+
Assert.Contains(
313+
"<Property Name=\"Address\" Type=\"System.Web.OData.Formatter.FormatterAddress\" Nullable=\"false\" />",
314+
responseString);
315+
316+
Assert.Contains(
317+
"<Property Name=\"Addresses\" Type=\"Collection(System.Web.OData.Formatter.FormatterAddress)\" Nullable=\"false\" />",
318+
responseString);
319+
}
320+
295321
private HttpConfiguration GetConfiguration()
296322
{
297323
var config = new[] { typeof(MetadataController) }.GetHttpConfiguration();

0 commit comments

Comments
 (0)