Skip to content

Commit

Permalink
Fix issue with property names which differ from Clr property names
Browse files Browse the repository at this point in the history
  • Loading branch information
KenitoInc authored and xuzhg committed Nov 29, 2023
1 parent fd74a5c commit 314dc62
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 8 deletions.
10 changes: 6 additions & 4 deletions src/Microsoft.AspNet.OData.Shared/ODataAPIHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ internal static void CopyObjectProperties(object resource, IEdmModel model, IODa
navigationProperties = edmEntityType.NavigationProperties();
}

IDictionary<string, object> keys = GetKeys(entityKey, resource, type); // Refactored ApplyHandler. Consider removing this.
IDictionary<string, object> keys = GetKeys(model, entityKey, resource, type); // Refactored ApplyHandler. Consider removing this.

IODataAPIHandler odataIdContainerHandler = null;

Expand All @@ -203,7 +203,8 @@ internal static void CopyObjectProperties(object resource, IEdmModel model, IODa
{
foreach (IEdmNavigationProperty navProp in navigationProperties)
{
navPropNames.Add(navProp.Name);
string clrPropertyName = EdmLibHelpers.GetClrPropertyName(navProp, model);
navPropNames.Add(clrPropertyName);
}
}

Expand Down Expand Up @@ -422,7 +423,7 @@ private static void CopyProperties(object originalObject, object newObject, List
}
}

private static IDictionary<string, object> GetKeys(IEnumerable<IEdmStructuralProperty> properties, object resource, Type type)
private static IDictionary<string, object> GetKeys(IEdmModel model, IEnumerable<IEdmStructuralProperty> properties, object resource, Type type)
{
IDictionary<string, object> keys = new Dictionary<string, object>();

Expand All @@ -433,7 +434,8 @@ private static IDictionary<string, object> GetKeys(IEnumerable<IEdmStructuralPro

foreach (IEdmStructuralProperty property in properties)
{
PropertyInfo prop = type.GetProperty(property.Name);
string clrPropertyName = EdmLibHelpers.GetClrPropertyName(property, model);
PropertyInfo prop = type.GetProperty(clrPropertyName);
object value = prop.GetValue(resource, null);

keys.Add(new KeyValuePair<string, object>(property.Name, value));
Expand Down
7 changes: 4 additions & 3 deletions src/Microsoft.AspNet.OData.Shared/Query/ExpandQueryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ private string GenerateExpandQueryStringInternal(object value, IEdmModel model,
foreach (IEdmNavigationProperty navProp in navigationProperties)
{
count++;
PropertyInfo prop = type.GetProperty(navProp.Name);
string clrPropertyName = EdmLibHelpers.GetClrPropertyName(navProp, model);
PropertyInfo prop = type.GetProperty(clrPropertyName);

if (isCollection)
{
Expand All @@ -86,7 +87,7 @@ private string GenerateExpandQueryStringInternal(object value, IEdmModel model,
if (!navPropNames.Contains(navProp.Name))
{
expandString += !isNestedExpand ? "" : "(";
expandString += count > 1 ? "," + prop.Name : string.Concat("$expand=", prop.Name);
expandString += count > 1 ? "," + navProp.Name : string.Concat("$expand=", navProp.Name);
navPropNames.Add(navProp.Name);
expandString += GenerateExpandQueryStringInternal(navPropValue, model, true);
}
Expand All @@ -108,7 +109,7 @@ private string GenerateExpandQueryStringInternal(object value, IEdmModel model,
if (!navPropNames.Contains(navProp.Name))
{
expandString += !isNestedExpand ? "" : "(";
expandString += count > 1 ? "," + prop.Name : string.Concat("$expand=", prop.Name);
expandString += count > 1 ? "," + navProp.Name : string.Concat("$expand=", navProp.Name);
navPropNames.Add(navProp.Name);
expandString += GenerateExpandQueryStringInternal(navPropValue, model, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -488,4 +488,36 @@ private void InitEmployees()
var cntrl = new EmployeesController();
}
}

public class StudentController : TestODataController
{
public static IList<Student> Students = null;
public static IList<Course> Courses = null;

public StudentController()
{
if (null == Students)
{
InitStudents();
}
}

private void InitStudents()
{
Students = new List<Student>();
Courses = new List<Course>();
}

[ODataRoute("Students")]
[HttpPost]
[EnableQuery]
public ITestActionResult Post([FromBody] Student student)
{
var handler = new StudentAPIHandler();

handler.DeepInsert(student, Request.GetModel(), new APIHandlerFactory(Request.GetModel()));

return Created(student);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Builder;

Expand Down Expand Up @@ -161,6 +162,32 @@ public class UnTypedAddress
public string Street { get; set; }
}

[DataContract]
public class Student
{
[Key]
[DataMember(Name="StudentId")]
public int Id { get; set; }

[DataMember(Name = "StudentName")]
public string Name { get; set; }

[DataMember(Name = "StudentCourses")]
public List<Course> Courses { get; set; }
}

[DataContract]
public class Course
{
[Key]
[DataMember(Name = "CourseId")]
public int Id { get; set; }

[DataMember(Name = "CourseName")]
public string Name { get; set; }
}


public class FriendColl<T> : ICollection<T>
{
public FriendColl() { _items = new List<T>(); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ public static IEdmModel GetConventionModel(WebRouteConfiguration configuration)
EntitySetConfiguration<NewOrder> overdueorders = builder.EntitySet<NewOrder>("OverdueOrders");
EntitySetConfiguration<MyNewOrder> myoverdueorders = builder.EntitySet<MyNewOrder>("MyOverdueOrders");
EntitySetConfiguration<NewOrder> myNewOrders = builder.EntitySet<NewOrder>("MyNewOrders");
EntitySetConfiguration<Student> students = builder.EntitySet<Student>("Students");
EntitySetConfiguration<Course> courses = builder.EntitySet<Course>("Courses");

// maybe following lines are not required once bug #1587 is fixed.
// 1587: It's better to support automatically adding actions and functions in ODataConventionModelBuilder.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1926,4 +1926,230 @@ public override ODataAPIResponseStatus TryAddRelatedObject(IEdmStructuredObject
return ODataAPIResponseStatus.Success;
}
}

internal class StudentAPIHandler : ODataAPIHandler<Student>
{
public override ODataAPIResponseStatus TryCreate(IDictionary<string, object> keyValues, out Student createdObject, out string errorMessage)
{
createdObject = null;
errorMessage = string.Empty;

try
{
createdObject = new Student();
StudentController.Students.Add(createdObject);

return ODataAPIResponseStatus.Success;
}
catch (Exception ex)
{
errorMessage = ex.Message;

return ODataAPIResponseStatus.Failure;
}
}

public override ODataAPIResponseStatus TryDelete(IDictionary<string, object> keyValues, out string errorMessage)
{
errorMessage = string.Empty;

try
{
var id = keyValues.First().Value.ToString();
var student = StudentController.Students.First(x => x.Id == Int32.Parse(id));

StudentController.Students.Remove(student);

return ODataAPIResponseStatus.Success;
}
catch (Exception ex)
{
errorMessage = ex.Message;

return ODataAPIResponseStatus.Failure;
}
}

public override ODataAPIResponseStatus TryGet(IDictionary<string, object> keyValues, out Student originalObject, out string errorMessage)
{
ODataAPIResponseStatus status = ODataAPIResponseStatus.Success;
errorMessage = string.Empty;
originalObject = null;

try
{
var id = keyValues["Id"].ToString();
originalObject = StudentController.Students.FirstOrDefault(x => x.Id == Int32.Parse(id));

if (originalObject == null)
{
status = ODataAPIResponseStatus.NotFound;
}
}
catch (Exception ex)
{
status = ODataAPIResponseStatus.Failure;
errorMessage = ex.Message;
}

return status;
}

public override IODataAPIHandler GetNestedHandler(Student parent, string navigationPropertyName)
{
switch (navigationPropertyName)
{
case "Courses":
return new CourseAPIHandler(parent);
default:
return null;
}
}

public override ODataAPIResponseStatus TryAddRelatedObject(Student resource, out string errorMessage)
{
errorMessage = string.Empty;

return ODataAPIResponseStatus.Success;
}

public override Task<ODataAPIResponseStatus> TryCreateAsync(IDictionary<string, object> keyValues, out Student createdObject, out string errorMessage)
{
throw new NotImplementedException();
}

public override Task<ODataAPIResponseStatus> TryGetAsync(IDictionary<string, object> keyValues, out Student originalObject, out string errorMessage)
{
throw new NotImplementedException();
}

public override Task<ODataAPIResponseStatus> TryDeleteAsync(IDictionary<string, object> keyValues, out string errorMessage)
{
throw new NotImplementedException();
}

public override Task<ODataAPIResponseStatus> TryAddRelatedObjectAsync(Student resource, out string errorMessage)
{
throw new NotImplementedException();
}

public override IODataAPIHandler GetNestedHandlerAsync(Student parent, string navigationPropertyName)
{
throw new NotImplementedException();
}
}

internal class CourseAPIHandler : ODataAPIHandler<Course>
{
Student student;
public CourseAPIHandler(Student student)
{
this.student = student;
}

public override ODataAPIResponseStatus TryCreate(IDictionary<string, object> keyValues, out Course createdObject, out string errorMessage)
{
createdObject = null;
errorMessage = string.Empty;

try
{
createdObject = new Course();
StudentController.Courses.Add(createdObject);

return ODataAPIResponseStatus.Success;
}
catch (Exception ex)
{
errorMessage = ex.Message;

return ODataAPIResponseStatus.Failure;
}
}

public override ODataAPIResponseStatus TryDelete(IDictionary<string, object> keyValues, out string errorMessage)
{
errorMessage = string.Empty;

try
{
var id = keyValues.First().Value.ToString();
var course = StudentController.Courses.First(x => x.Id == Int32.Parse(id));

StudentController.Courses.Remove(course);

return ODataAPIResponseStatus.Success;
}
catch (Exception ex)
{
errorMessage = ex.Message;

return ODataAPIResponseStatus.Failure;
}
}

public override ODataAPIResponseStatus TryGet(IDictionary<string, object> keyValues, out Course originalObject, out string errorMessage)
{
ODataAPIResponseStatus status = ODataAPIResponseStatus.Success;
errorMessage = string.Empty;
originalObject = null;

try
{
var id = keyValues["Id"].ToString();
originalObject = StudentController.Courses.FirstOrDefault(x => x.Id == Int32.Parse(id));

if (originalObject == null)
{
status = ODataAPIResponseStatus.NotFound;
}
}
catch (Exception ex)
{
status = ODataAPIResponseStatus.Failure;
errorMessage = ex.Message;
}

return status;
}

public override IODataAPIHandler GetNestedHandler(Course parent, string navigationPropertyName)
{
return null;
}

public override ODataAPIResponseStatus TryAddRelatedObject(Course resource, out string errorMessage)
{
errorMessage = string.Empty;

this.student.Courses.Add(resource);

return ODataAPIResponseStatus.Success;
}

public override Task<ODataAPIResponseStatus> TryCreateAsync(IDictionary<string, object> keyValues, out Course createdObject, out string errorMessage)
{
throw new NotImplementedException();
}

public override Task<ODataAPIResponseStatus> TryGetAsync(IDictionary<string, object> keyValues, out Course originalObject, out string errorMessage)
{
throw new NotImplementedException();
}

public override Task<ODataAPIResponseStatus> TryDeleteAsync(IDictionary<string, object> keyValues, out string errorMessage)
{
throw new NotImplementedException();
}

public override Task<ODataAPIResponseStatus> TryAddRelatedObjectAsync(Course resource, out string errorMessage)
{
throw new NotImplementedException();
}

public override IODataAPIHandler GetNestedHandlerAsync(Course parent, string navigationPropertyName)
{
throw new NotImplementedException();
}
}
}
Loading

0 comments on commit 314dc62

Please sign in to comment.