存储库模式仅检索所需的列

我在这里使用示例来创建一个包含工作单元的存储库模式。

在代码中,有一个通用的Get方法:

public class GenericRepository where TEntity : class { internal AdminDbContext context; internal DbSet dbSet; public GenericRepository(AdminDbContext context) { this.context = context; this.dbSet = context.Set(); } public virtual IEnumerable Get( Expression<Func> filter = null, Func selector = null, Func<IQueryable, IOrderedQueryable> orderBy = null, string includeProperties = "") { IQueryable query = dbSet; if (filter != null) { query = query.Where(filter); } foreach (var includeProperty in includeProperties.Split (new char[] { ','}, StringSplitOptions.RemoveEmptyEntries)) { query = query.Include(includeProperty); } if (orderBy != null) { return orderBy(query).ToList(); } else { return query.ToList(); } } 

此时调用此方法时,将获取数据库中的所有记录,并在内存中完成列选择。

我的问题是如何在这里扩展Get方法,这将允许我动态地将列名称传递给此方法,以便在数据库级别只选择所需的列?

我试过了:

  • 接受带有所需列的逗号分隔值的字符串参数,但我无法将它们映射到实体。
  • 使用相同类型的filter创建一个给出错误的参数。

这是一个很长的答案,但这是我为此创建的扩展方法。 我在这种情况下返回一个对象,因为这在webAPI中用于返回json而我不需要特定的类型,但是这可以很容易地适用于返回通用实体类型。

 using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using Newtonsoft.Json.Linq; namespace Your.Extensions { public enum PropertyFormat { AsIs, PascalCase, CamelCase } public static class DataShapingExtensions { public static object ToDataShape(this ObjectIn objectToShape, string fields, PropertyFormat propertyFormat = PropertyFormat.AsIs) where ObjectIn : class { var listOfFields = new List(); if (!string.IsNullOrWhiteSpace(fields)) { listOfFields = fields.ToLower().Split(',').ToList(); } if (listOfFields.Any()) { var objectToReturn = new JObject(); //==== var enumerable = objectToShape as IEnumerable; if (enumerable != null) { var listOfObjects = new List(); foreach (var item in enumerable) { var objectToReturn2 = new JObject(); listOfFields.ForEach(field => { try { var prop = item.GetType() .GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); var fieldName = prop.Name; var fieldValue = prop.GetValue(item, null); fieldName = GetName(fieldName, propertyFormat); objectToReturn2.Add(new JProperty(fieldName, fieldValue)); } catch (Exception ex) { } }); listOfObjects.Add(objectToReturn2); } return listOfObjects.ConvertAll(o => o); } //==== listOfFields.ForEach(field => { try { var prop = objectToShape.GetType() .GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); var fieldName = prop.Name; var fieldValue = prop.GetValue(objectToShape, null); fieldName = GetName(fieldName, propertyFormat); objectToReturn.Add(new JProperty(fieldName, fieldValue)); } catch (Exception ex) { } }); return objectToReturn; } return objectToShape; } private static string GetName(string field, PropertyFormat propertyFormat) { switch (propertyFormat) { case PropertyFormat.AsIs: return field; case PropertyFormat.PascalCase: return field.ToPascalCase(); case PropertyFormat.CamelCase: return field.ToCamelCase(); default: return field; } } } } 

//用法

 [HttpGet, Route("api/someroute")] public async Task YourMethod(string fields = null) { try { var products = await yourRepo.GetProductsList(); if (fields.HasValue()) { return Ok(products.ToDataShape(fields, PropertyFormat.CamelCase)); } return Ok(products); } catch (Exception) { return InternalServerError(); } } 

//呼叫路由

 /api/someroute?fields=productID,productName 

//输出(json)

 { productID: 1, productName: "Some Name" }