深度优先

这个家伙好懒,除了文章什么都没留下

0%

【EF】查询根据字段动态排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using XXX.Infrastructure.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Dynamic.Core;

namespace XXX.Infrastructure.Extensions
{
public static class QueryableExtensions
{
public static IQueryable<T> ApplySort<T>(this IQueryable<T> source, string orderBy, IPropertyMapping propertyMapping)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}

if (propertyMapping == null)
{
throw new ArgumentNullException(nameof(propertyMapping));
}

var mappingDictionary = propertyMapping.MappingDictionary;
if (mappingDictionary == null)
{
throw new ArgumentNullException(nameof(mappingDictionary));
}

if (string.IsNullOrWhiteSpace(orderBy))
{
return source;
}

var orderByAfterSplit = orderBy.Split(',');
foreach (var orderByClause in orderByAfterSplit.Reverse())
{
var trimmedOrderByClause = orderByClause.Trim();
var orderDescending = trimmedOrderByClause.EndsWith(" desc");
var indexOfFirstSpace = trimmedOrderByClause.IndexOf(" ", StringComparison.Ordinal);
var propertyName = indexOfFirstSpace == -1 ?
trimmedOrderByClause : trimmedOrderByClause.Remove(indexOfFirstSpace);
if (string.IsNullOrEmpty(propertyName))
{
continue;
}
if (!mappingDictionary.TryGetValue(propertyName, out List<MappedProperty> mappedProperties))
{
throw new ArgumentException($"Key mapping for {propertyName} is missing");
}
if (mappedProperties == null)
{
throw new ArgumentNullException(propertyName);
}
mappedProperties.Reverse();
foreach (var destinationProperty in mappedProperties)
{
if (destinationProperty.Revert)
{
orderDescending = !orderDescending;
}
source = source.OrderBy(destinationProperty.Name + (orderDescending ? " descending" : " ascending"));
}
}

return source;
}

public static IQueryable<object> ToDynamicQueryable<TSource>
(this IQueryable<TSource> source, string fields, Dictionary<string, List<MappedProperty>> mappingDictionary)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}

if (mappingDictionary == null)
{
throw new ArgumentNullException(nameof(mappingDictionary));
}

if (string.IsNullOrWhiteSpace(fields))
{
return (IQueryable<object>)source;
}

fields = fields.ToLower();
var fieldsAfterSplit = fields.Split(',').ToList();
if (!fieldsAfterSplit.Contains("id", StringComparer.InvariantCultureIgnoreCase))
{
fieldsAfterSplit.Add("id");
}
var selectClause = "new (";

foreach (var field in fieldsAfterSplit)
{
var propertyName = field.Trim();
if (string.IsNullOrEmpty(propertyName))
{
continue;
}

var key = mappingDictionary.Keys.SingleOrDefault(k => String.CompareOrdinal(k.ToLower(), propertyName.ToLower()) == 0);
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException($"Key mapping for {propertyName} is missing");
}
var mappedProperties = mappingDictionary[key];
if (mappedProperties == null)
{
throw new ArgumentNullException(key);
}
foreach (var destinationProperty in mappedProperties)
{
selectClause += $" {destinationProperty.Name},";
}
}

selectClause = selectClause.Substring(0, selectClause.Length - 1) + ")";
return (IQueryable<object>)source.Select(selectClause);
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
 using System;
using System.Collections.Generic;
using System.Text;

namespace XXX.Infrastructure.Services
{
public interface IPropertyMapping
{
Dictionary<string, List<MappedProperty>> MappingDictionary { get; }
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 using XXX.Core.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;

namespace XXX.Infrastructure.Services
{
public abstract class PropertyMapping<TSource, TDestination> : IPropertyMapping
where TDestination : IEntity
{
public Dictionary<string, List<MappedProperty>> MappingDictionary { get; }

protected PropertyMapping(Dictionary<string, List<MappedProperty>> mappingDictionary)
{
MappingDictionary = mappingDictionary;
MappingDictionary[nameof(IEntity.Id)] = new List<MappedProperty>
{
new MappedProperty { Name = nameof(IEntity.Id), Revert = false}
};
}
}
}

1
query = query.ApplySort(postParameters.OrderBy, _propertyMappingContainer.Resolve<PostResource, Post>());
1
2
3
4
5
6
 public interface IPropertyMappingContainer
{
void Register<T>() where T : IPropertyMapping, new();
IPropertyMapping Resolve<TSource, TDestination>() where TDestination : IEntity;
bool ValidateMappingExistsFor<TSource, TDestination>(string fields) where TDestination : IEntity;
}

Startup.cs

1
2
3
4
var propertyMappingContainer = new PropertyMappingContainer();
propertyMappingContainer.Register<PostPropertyMapping>();
propertyMappingContainer.Register<ArticlePropertyMapping>();
services.AddSingleton<IPropertyMappingContainer>(propertyMappingContainer);