Skip to content
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

Support Enums as Keys in OData Client #3013

Merged
merged 8 commits into from
Jul 22, 2024
4 changes: 3 additions & 1 deletion src/Microsoft.OData.Client/Metadata/ODataTypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,9 @@ private PropertyInfo[] GetKeyProperties()
throw c.Error.InvalidOperation(c.Strings.ClientType_KeysOnDifferentDeclaredType(typeName));
}

if (!PrimitiveType.IsKnownType(key.PropertyType) && !(key.PropertyType.GetGenericTypeDefinition() == typeof(System.Nullable<>) && key.PropertyType.GetGenericArguments().First().IsEnum()))
// Check if the key property's type is a known primitive, an enum, or a nullable generic.
// If it doesn't meet any of these conditions, throw an InvalidOperationException.
if (!PrimitiveType.IsKnownType(key.PropertyType) && !key.PropertyType.IsEnum() && !(key.PropertyType.IsGenericType() && key.PropertyType.GetGenericTypeDefinition() == typeof(System.Nullable<>) && key.PropertyType.GetGenericArguments().First().IsEnum()))
{
throw c.Error.InvalidOperation(c.Strings.ClientType_KeysMustBeSimpleTypes(key.Name, typeName, key.PropertyType.FullName));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

using Microsoft.OData.Client.Metadata;
using System;
using System.Linq;
using System.Reflection;
using Xunit;

namespace Microsoft.OData.Client.Tests.Metadata
Expand Down Expand Up @@ -50,6 +52,99 @@ public void IFTypeProperty_HasKeyAttributeAndOneProperty_TypeIsEntityAndDoesNotT
Assert.True(actualResult);
}

[Fact]
public void IFType_HasMultipleKeyAttributesWhereOneIsEnum_TypeIsEntityAndDoesNotThrowException()
{
//Arrange
Type employee = typeof(Employee);

//Act
bool actualResult = ClientTypeUtil.TypeOrElementTypeIsEntity(employee);

//Assert
Assert.True(actualResult);
}

[Fact]
public void IFTypeProperty_HasMultipleKeyAttributes_GetKeyPropertiesOnType_DoesNotThrowException()
{
//Arrange
Type employee = typeof(Employee);

int expectedNumberOfKeyProperties = 4; // 2 Primitive Known Types, 1 Enum Type, 1 Enum Nullable Generic Type

//Act
PropertyInfo[] keyProperties = ClientTypeUtil.GetKeyPropertiesOnType(employee);

//Assert
Assert.Equal(expectedNumberOfKeyProperties, keyProperties.Length);
WanjohiSammy marked this conversation as resolved.
Show resolved Hide resolved
}

[Fact]
public void IFTypeProperty_HasEnumTypeKeyAttribute_GetKeyPropertiesOnType_DoesNotThrowException()
{
// Arrange
Type employee = typeof(Employee);

//Act
PropertyInfo[] keyProperties = ClientTypeUtil.GetKeyPropertiesOnType(employee);
PropertyInfo key = keyProperties.Single(k => k.Name == "EmpType");

//Assert
Assert.True(key.PropertyType.IsEnum());
Assert.True(key.PropertyType == typeof(EmployeeType));
}

[Fact]
public void IFTypeProperty_HasKnownPrimitiveTypesKeyAttributes_GetKeyPropertiesOnType_DoesNotThrowException()
{
// Arrange
Type employee = typeof(Employee);

//Act
PropertyInfo[] keyProperties = ClientTypeUtil.GetKeyPropertiesOnType(employee);

PropertyInfo empNumKey = keyProperties.Single(k => k.Name == "EmpNumber");
PropertyInfo deptNumKey = keyProperties.Single(k => k.Name == "DeptNumber");

//Assert
Assert.True(PrimitiveType.IsKnownType(empNumKey.PropertyType) && empNumKey.PropertyType == typeof(int));
Assert.True(PrimitiveType.IsKnownType(deptNumKey.PropertyType) && deptNumKey.PropertyType == typeof(string));
}

[Fact]
public void IFTypeProperty_HasNullableGenericTypeKeyAttribute_OfTypeEnum_GetKeyPropertiesOnType_DoesNotThrowException()
{
// Arrange
Type employee = typeof(Employee);

//Act
PropertyInfo[] keyProperties = ClientTypeUtil.GetKeyPropertiesOnType(employee);
PropertyInfo key = keyProperties.Single(k => k.Name == "NullableEmpType");

//Assert
Assert.True(key.PropertyType.IsGenericType);
Assert.True(key.PropertyType == typeof(System.Nullable<EmployeeType>));
}

[Fact]
public void IFTypeProperty_HasNullableGenericTypeKey_OfTypeStruct_GetKeyPropertiesOnType_ThrowsException()
{
// Arrange
Type employee = typeof(EmployeeWithNullableStruct);

PropertyInfo empTypeStructKey = employee.GetProperty("EmpTypeStruct");

InvalidOperationException expectedException = Error.InvalidOperation(Strings.ClientType_KeysMustBeSimpleTypes(empTypeStructKey.Name, employee.ToString(), empTypeStructKey.PropertyType.FullName));

//Act
InvalidOperationException actualException = Assert.Throws<InvalidOperationException>(() => ClientTypeUtil.GetKeyPropertiesOnType(employee));

//Assert
Assert.NotNull(actualException);
Assert.Equal(expectedException.Message, actualException.Message);
}

public class Person
{
[System.ComponentModel.DataAnnotations.Key]
Expand All @@ -69,5 +164,55 @@ public class Car
public int NonStandardId { get; set; }
}

public class Employee
{
[System.ComponentModel.DataAnnotations.Key]
public int EmpNumber { get; set; }

[System.ComponentModel.DataAnnotations.Key]
public string DeptNumber { get; set; }

[System.ComponentModel.DataAnnotations.Key]
public EmployeeType EmpType { get; set; }

[System.ComponentModel.DataAnnotations.Key]
public EmployeeType? NullableEmpType { get; set; }

public string Name { get; set; }

[System.ComponentModel.DataAnnotations.Schema.ForeignKey("DeptNumber")]
public Department Department { get; set; }
}

public class EmployeeWithNullableStruct
{
[System.ComponentModel.DataAnnotations.Key]
public int EmpNumber { get; set; }

[System.ComponentModel.DataAnnotations.Key]
public EmployeeTypeStruct? EmpTypeStruct { get; set; }

public string Name { get; set; }
}

public enum EmployeeType
{
None = 1,
FullTime = 2,
PartTime = 3
}

public class Department
{
[System.ComponentModel.DataAnnotations.Key]
public string DeptId { get; set; }
public string Name { get; set; }
}

public struct EmployeeTypeStruct
{
public int EmpTypeId { get; set; }
}

}
}
Loading