Skip to content

Commit

Permalink
[Codeplex issue #2027] [Required] attribute doesn't work on a propert…
Browse files Browse the repository at this point in the history
…y of

Complex type.

Actually, all property conventions should be re-applyed to the new
property if the entity type reconfiged to complex type.
  • Loading branch information
xuzhg committed Aug 6, 2014
1 parent 27e6385 commit 19522b4
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,14 @@ private void ReconfigureEntityTypesAsComplexType(EntityTypeConfiguration[] misco
propertyConfiguration = entityToBePatched.AddComplexProperty(propertyToBeRemoved.PropertyInfo);
}

Contract.Assert(propertyToBeRemoved.AddedExplicitly == false);

// The newly added property must be marked as added implicitly. This can make sure the property
// conventions can be re-applied to the new property.
propertyConfiguration.AddedExplicitly = false;

ReapplyPropertyConvention(propertyConfiguration, entityToBePatched);

propertyConfiguration.Name = propertyNameAlias;
}
}
Expand Down Expand Up @@ -815,6 +823,15 @@ private void ApplyPropertyConvention(IEdmPropertyConvention propertyConvention,
}
}

private void ReapplyPropertyConvention(PropertyConfiguration property,
StructuralTypeConfiguration edmTypeConfiguration)
{
foreach (IEdmPropertyConvention propertyConvention in _conventions.OfType<IEdmPropertyConvention>())
{
propertyConvention.Apply(property, edmTypeConfiguration, this);
}
}

private static Dictionary<Type, List<Type>> BuildDerivedTypesMapping(IAssembliesResolver assemblyResolver)
{
IEnumerable<Type> allTypes = TypeHelper.GetLoadedTypes(assemblyResolver).Where(t => t.IsVisible && t.IsClass && t != typeof(object));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,40 @@ public void ODataConventionModelBuilder_MappedDerivedTypeHasNoAliasedBasePropert
Assert.Equal("Heads", property.Name);
}

[Fact]
public void ODataConventionModelBuilder_RequiredAttribute_WorksOnComplexTypeProperty()
{
// Arrange
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<RequiredEmployee>("Employees");

// Act
IEdmModel model = builder.GetEdmModel();

// Assert
IEdmEntityType entityType = model.AssertHasEntityType(typeof(RequiredEmployee));
IEdmProperty property = Assert.Single(entityType.DeclaredProperties.Where(e => e.Name == "Address"));
Assert.False(property.Type.IsNullable);
}

[Fact]
public void ODataConventionModelBuilder_QueryLimitAttributes_WorksOnComplexTypeProperty()
{
// Arrange
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<QueryLimitEmployee>("Employees");

// Act
IEdmModel model = builder.GetEdmModel();

// Assert
IEdmEntityType entityType = model.AssertHasEntityType(typeof(QueryLimitEmployee));
IEdmProperty property = Assert.Single(entityType.DeclaredProperties.Where(e => e.Name == "Address"));

Assert.True(EdmLibHelpers.IsNonFilterable(property, model));
Assert.True(EdmLibHelpers.IsUnsortable(property, model));
}

[Fact]
public void ODataConventionModelBuilder_GetEdmModel_ThrowsException_IfHasDateTimeProperty()
{
Expand Down Expand Up @@ -1903,6 +1937,28 @@ public class DerivedManager : BaseEmployee
public int Heads { get; set; }
}

public class RequiredEmployee
{
public int Id { get; set; }

[Required]
public EmployeeAddress Address { get; set; }
}

public class QueryLimitEmployee
{
public int Id { get; set; }

[NonFilterable]
[Unsortable]
public EmployeeAddress Address { get; set; }
}

public class EmployeeAddress
{
public string City { get; set; }
}

public enum Gender
{
Male = 1,
Expand Down
14 changes: 14 additions & 0 deletions OData/test/System.Web.OData.Test/OData/Formatter/ODataTestUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,18 @@ public class FormatterAddress
public string City { get; set; }
public IDictionary<string, object> Properties { get; set; }
}

public class FormatterAccount
{
public int Id { get; set; }

[Required]
public string Name { get; set; }

[Required]
public FormatterAddress Address { get; set; }

[Required]
public IList<FormatterAddress> Addresses { get; set; }
}
}
26 changes: 26 additions & 0 deletions OData/test/System.Web.OData.Test/OData/MetadataControllerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,32 @@ public void Controller_DoesNotAppear_InApiDescriptions()
Assert.DoesNotContain("ODataMetadata", apis);
}

[Fact]
public void RequiredAttribute_Works_OnComplexTypeProperty()
{
// Arrange
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<FormatterAccount>("Accounts");

var config = new[] { typeof(MetadataController) }.GetHttpConfiguration();
config.MapODataServiceRoute(builder.GetEdmModel());

HttpServer server = new HttpServer(config);
HttpClient client = new HttpClient(server);

// Act
var responseString = client.GetStringAsync("http://localhost/$metadata").Result;

// Assert
Assert.Contains(
"<Property Name=\"Address\" Type=\"System.Web.OData.Formatter.FormatterAddress\" Nullable=\"false\" />",
responseString);

Assert.Contains(
"<Property Name=\"Addresses\" Type=\"Collection(System.Web.OData.Formatter.FormatterAddress)\" Nullable=\"false\" />",
responseString);
}

private HttpConfiguration GetConfiguration()
{
var config = new[] { typeof(MetadataController) }.GetHttpConfiguration();
Expand Down

0 comments on commit 19522b4

Please sign in to comment.