diff --git a/src/BccCode.Linq/Client/QueryProvider/ApiQueryProvider.cs b/src/BccCode.Linq/Client/QueryProvider/ApiQueryProvider.cs index 3d9bb50..735d59b 100644 --- a/src/BccCode.Linq/Client/QueryProvider/ApiQueryProvider.cs +++ b/src/BccCode.Linq/Client/QueryProvider/ApiQueryProvider.cs @@ -3,8 +3,10 @@ using System.Globalization; using System.Linq.Expressions; using System.Reflection; +using System.Runtime.Serialization; using System.Text; using BccCode.Platform; +using Newtonsoft.Json; namespace BccCode.Linq.Client; @@ -385,7 +387,32 @@ protected override Expression VisitMember(MemberExpression node) { if (_activeParameters.TryGetValue(parameterNode, out var apiCaller)) { - string ApiMemberName() => node.Member.Name.ToCamelCase(); + string ApiMemberToJsonString(MemberInfo member) + { + var dataMemberAttribute = member.GetCustomAttribute(); + if (dataMemberAttribute != null) + { + return dataMemberAttribute.Name; + } + +#if NET6_0_OR_GREATER + var jsonPropertyNameAttribute = member.GetCustomAttribute(); + if (jsonPropertyNameAttribute != null) + { + return jsonPropertyNameAttribute.Name; + } +#endif + + var jsonPropertyAttribute = member.GetCustomAttribute(); + if (jsonPropertyAttribute != null) + { + return jsonPropertyAttribute.PropertyName ?? member.Name.ToCamelCase(); + } + + return member.Name.ToCamelCase(); + } + + string ApiMemberName() => ApiMemberToJsonString(node.Member); string ApiMemberPath(string splitter = ".") { @@ -394,7 +421,7 @@ string ApiMemberPath(string splitter = ".") foreach (var nestedMemberExpression in nestedMemberExpressions) { memberPath.Append( - nestedMemberExpression.Member.Name.ToCamelCase() + ApiMemberToJsonString(nestedMemberExpression.Member) ); memberPath.Append(splitter); } @@ -486,6 +513,7 @@ string ApiMemberPath(string splitter = ".") case VisitLinqLambdaMode.Convert: { //We assume conversion is implicitly handled on the server side + Debug.Assert(_where != null); _where.Append(ApiMemberPath(splitter: "\": {\"")); return Expression.Empty(); } diff --git a/tests/BccCode.Linq.Tests/Helpers/TestClass.cs b/tests/BccCode.Linq.Tests/Helpers/TestClass.cs index b56cb67..d753534 100644 --- a/tests/BccCode.Linq.Tests/Helpers/TestClass.cs +++ b/tests/BccCode.Linq.Tests/Helpers/TestClass.cs @@ -1,4 +1,8 @@ -namespace BccCode.Linq.Tests.Helpers; +using System.Runtime.Serialization; +using System.Text.Json.Serialization; +using Newtonsoft.Json; + +namespace BccCode.Linq.Tests.Helpers; public class TestClass { @@ -20,6 +24,15 @@ public class TestClass #if NET6_0_OR_GREATER public DateOnly DateOnly { get; set; } #endif + + [DataMember(Name = "custom_name")] + public NestedClass CustomNameByDataMemberAttribute { get; set; } + + [JsonPropertyName("custom_name")] + public NestedClass CustomNameByJsonPropertyNameAttribute { get; set; } + + [JsonProperty("custom_name")] + public NestedClass CustomNameByNewtonsoftJsonPropertyAttribute { get; set; } } public class NestedClass diff --git a/tests/BccCode.Linq.Tests/LinqTests.cs b/tests/BccCode.Linq.Tests/LinqTests.cs index c34c6c7..8429a1a 100644 --- a/tests/BccCode.Linq.Tests/LinqTests.cs +++ b/tests/BccCode.Linq.Tests/LinqTests.cs @@ -2285,6 +2285,60 @@ public void IncludeThenIncludeAfterEnumerableTest() Assert.Equal(5, persons.Count); } + [Fact] + public void IncludeCustomNameByDataMemberAttributeTest() + { + var api = new ApiClientMockup(); + + var query = api.Empty + .Include(p => p.CustomNameByDataMemberAttribute); + + var emptyList = query.ToList(); + Assert.Equal("empty", api.PageEndpoint); + Assert.Null(api.ClientQuery?.Filter); + Assert.Equal("*,custom_name.*", api.ClientQuery?.Fields); + Assert.Null(api.ClientQuery?.Sort); + Assert.Null(api.ClientQuery?.Offset); + Assert.Null(api.ClientQuery?.Limit); + Assert.Empty(emptyList); + } + + [Fact] + public void IncludeCustomNameByJsonPropertyNameAttributeTest() + { + var api = new ApiClientMockup(); + + var query = api.Empty + .Include(p => p.CustomNameByJsonPropertyNameAttribute); + + var emptyList = query.ToList(); + Assert.Equal("empty", api.PageEndpoint); + Assert.Null(api.ClientQuery?.Filter); + Assert.Equal("*,custom_name.*", api.ClientQuery?.Fields); + Assert.Null(api.ClientQuery?.Sort); + Assert.Null(api.ClientQuery?.Offset); + Assert.Null(api.ClientQuery?.Limit); + Assert.Empty(emptyList); + } + + [Fact] + public void IncludeCustomNameByNewtonsoftJsonPropertyAttributeTest() + { + var api = new ApiClientMockup(); + + var query = api.Empty + .Include(p => p.CustomNameByNewtonsoftJsonPropertyAttribute); + + var emptyList = query.ToList(); + Assert.Equal("empty", api.PageEndpoint); + Assert.Null(api.ClientQuery?.Filter); + Assert.Equal("*,custom_name.*", api.ClientQuery?.Fields); + Assert.Null(api.ClientQuery?.Sort); + Assert.Null(api.ClientQuery?.Offset); + Assert.Null(api.ClientQuery?.Limit); + Assert.Empty(emptyList); + } + #endregion