在Asp .net core 中通過屬性對映實現動態排序和資料塑形
阿新 • • 發佈:2021-08-27
目錄
屬性對映服務實現
public class PropertyMappingValue
{
public IEnumerable<string> DestinationProperties { get; private set; }
public PropertyMappingValue(IEnumerable<string> destinationProperties)
{
DestinationProperties = destinationProperties;
}
}
public class PropertyMapping<TSource, TDestination> : IPropertyMapping { public Dictionary<string, PropertyMappingValue> _mappingDictionary { get; set; } public PropertyMapping(Dictionary<string, PropertyMappingValue> mappingDictionary) { _mappingDictionary = mappingDictionary; } }
public class PropertyMappingService : IPropertyMappingService { //PropertyMapping private Dictionary<string, PropertyMappingValue> _touristRoutePropertyMapping = new Dictionary<string, PropertyMappingValue>(StringComparer.OrdinalIgnoreCase) { {"Id", new PropertyMappingValue(new List<string>(){"Id"}) }, {"Title", new PropertyMappingValue(new List<string>(){"Title"}) }, {"Rating", new PropertyMappingValue(new List<string>(){"Rating"}) }, {"OriginalPrice", new PropertyMappingValue(new List<string>(){"OriginalPrice"})}, }; //PropertyMappings private IList<IPropertyMapping> _propertyMappings = new List<IPropertyMapping>(); public PropertyMappingService() { _propertyMappings.Add( new PropertyMapping<TouristRouteDto, TouristRoute> (_touristRoutePropertyMapping) ); } //GetPropertyMapping public Dictionary<string, PropertyMappingValue> GetPropertyMapping<TSource, TDestination>() { var matchingMapping = _propertyMappings.OfType<PropertyMapping<TSource, TDestination>>(); if (matchingMapping.Count() == 1) { return matchingMapping.First()._mappingDictionary; } throw new Exception($"Cannot find exact property mapping instance for <{typeof(TSource)}, {typeof(TDestination)}>"); } //IsMappingExists public bool IsMappingExists<TSource, TDestination>(string fields) { var propertyMapping = GetPropertyMapping<TSource, TDestination>(); if (string.IsNullOrWhiteSpace(fields)) { return true; } var fieldsAfterSplit = fields.Split(","); foreach (var field in fieldsAfterSplit) { var trimmedField = field.Trim(); var indexOfFirstSpace = trimmedField.IndexOf(" "); var propertyName = indexOfFirstSpace == -1 ? trimmedField : trimmedField.Remove(indexOfFirstSpace); if (!propertyMapping.ContainsKey(propertyName)) { return false; } } return true; } //IsPropertiesExists public bool IsPropertiesExists<T>(string fields) { if (string.IsNullOrWhiteSpace(fields)) { return true; } var fieldsAfterSplit = fields.Split(','); foreach (var field in fieldsAfterSplit) { var propertyName = field.Trim(); var propertyInfo = typeof(T) .GetProperty( propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance ); if (propertyInfo == null) { return false; } } return true; } }
注入服務
動態排序
在Helper中擴充套件IQueryable封裝了ApplySort方法實現動態排序
public static class IQueryableExtensions { public static IQueryable<T> ApplySort<T>( this IQueryable<T> source, string orderBy, Dictionary<string, PropertyMappingValue> mappingDictionary ) { if (source == null) { throw new ArgumentNullException("source"); } if (mappingDictionary == null) { throw new ArgumentNullException("mappingDictionary"); } if (string.IsNullOrWhiteSpace(orderBy)) { return source; } var orderByString = string.Empty; var orderByAfterSplit = orderBy.Split(','); foreach (var order in orderByAfterSplit) { var trimmedOrder = order.Trim(); var orderDescending = trimmedOrder.EndsWith(" desc"); var indexOfFirstSpace = trimmedOrder.IndexOf(" "); var propertyName = indexOfFirstSpace == -1 ? trimmedOrder : trimmedOrder.Remove(indexOfFirstSpace); if (!mappingDictionary.ContainsKey(propertyName)) { throw new ArgumentException($"Key mapping for {propertyName} is missing"); } var propertyMappingValue = mappingDictionary[propertyName]; if (propertyMappingValue == null) { throw new ArgumentNullException("propertyMappingValue"); } foreach (var destinationProperty in propertyMappingValue.DestinationProperties) { orderByString = orderByString + (string.IsNullOrWhiteSpace(orderByString) ? string.Empty : ", ") + destinationProperty + (orderDescending ? " descending" : " ascending"); } } return source.OrderBy(orderByString); } }
在repository中使用
資料塑形
安裝Nuget包
在Helper中封裝了IEnumerableExtensions、ObjectExtensions,實現對資料的動態塑形。
public static class IEnumerableExtensions
{
public static IEnumerable<ExpandoObject> ShapeData<TSource>(
this IEnumerable<TSource> source,
string fields
)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var expandoObjectList = new List<ExpandoObject>();
//避免在列表中遍歷資料,建立一個屬性資訊列表
var propertyInfoList = new List<PropertyInfo>();
if (string.IsNullOrWhiteSpace(fields))
{
// 希望返回動態型別物件ExpandoObject所有的屬性
var propertyInfos = typeof(TSource)
.GetProperties(BindingFlags.IgnoreCase
| BindingFlags.Public | BindingFlags.Instance);
propertyInfoList.AddRange(propertyInfos);
}
else
{
//逗號來分隔欄位字串
var fieldsAfterSplit = fields.Split(',');
foreach (var filed in fieldsAfterSplit)
{
// 去掉首尾多餘的空格,獲得屬性名稱
var propertyName = filed.Trim();
var propertyInfo = typeof(TSource)
.GetProperty(propertyName, BindingFlags.IgnoreCase
| BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
{
throw new Exception($"屬性 {propertyName} 找不到" +
$" {typeof(TSource)}");
}
propertyInfoList.Add(propertyInfo);
}
}
foreach (TSource sourceObject in source)
{
// 建立動態型別物件, 建立資料塑性物件
var dataShapedObject = new ExpandoObject
foreach (var propertyInfo in propertyInfoList)
{
//獲得對應屬性的真實資料
var propertyValue = propertyInfo.GetValue(sourceObjec
((IDictionary<string, object>)dataShapedObject)
.Add(propertyInfo.Name, propertyValue);
expandoObjectList.Add(dataShapedObject);
}
return expandoObjectList;
}
}
public static class ObjectExtensions
{
public static ExpandoObject ShapeData<TSource>(
this TSource source,
string fields
)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var dataShapedObject = new ExpandoObject();
if (string.IsNullOrWhiteSpace(fields))
{
var propertyInfos = typeof(TSource)
.GetProperties(BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in propertyInfos)
{
var propertyValue = propertyInfo.GetValue(source);
((IDictionary<string, object>)dataShapedObject)
.Add(propertyInfo.Name, propertyValue);
}
return dataShapedObject;
}
var fieldsAfterSplit = fields.Split(',');
foreach (var field in fieldsAfterSplit)
{
var propertyName = field.Trim();
var propertyInfo = typeof(TSource)
.GetProperty(propertyName,
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
{
throw new Exception($"Property {propertyName} wasn't found " +
$"on {typeof(TSource)}");
}
var propertyValue = propertyInfo.GetValue(source);
((IDictionary<string, object>)dataShapedObject)
.Add(propertyInfo.Name, propertyValue);
}
return dataShapedObject;
}
}
在控制器的Action中使用