实体的动态 linq 以符合 DRY

dynamic linq to entities to comply with DRY

有没有办法动态地执行以下操作,这样我就不必重复自己了?

var result = from c in _Entities.Cars 
where c.Colour == "White"
select c;

var result = from m in _Entities.Bikes 
where m.Colour == "White"
select m;

etc...

如:

var entities = new List<string> {"Cars", "Bikes"};
foreach (var e in entities)
{
    var result = from m in e //pseudo code
    where m.Colour == "White"
    select m;
}

如果 Cars 和 Bikes 实现一个公共接口,比如 IVehicle,它有颜色 属性,您可以定义一个函数:

public IEnumerable<IVehicle> GetWhiteVehicles(IEnumerable<IVehicle> vehicles) {
  return vehicles.Where(p => p.Colour == "White");
}

然后

var result = GetWhiteVehicles(_Entities.Cars);
var result = GetWhiteVehicles(_Entities.Bikes);

如果汽车和自行车是从 Entity Framework 生成的 类,您仍然可以通过添加一个新的源文件来使它们实现一个接口,其中包含 类 的部分定义同名:

public partial class Bikes : IVehicle { }
public partial class Cars : IVehicle { }

这应该有效:

var entities = new List<List<dynamic>> {_Entities.Cars.ToList<dynamic>(), _Entitites.Bikes.ToList<dynamic>()};
foreach (var l in entities)
{
    var result = from m in l
        where m.Colour == "White"
        select m;
}

因此您可以避免对您的业务模型进行任何更改。然而,因此 dynamic 类型仅在运行时解析,无法确保 属性 Colour 确实存在于该类型上。

添加一个包含颜色的界面(IColorful)。设置您的汽车和自行车以实现该接口。创建并调用函数:

List<IColorful> FindByColor(IEnumerable<IColorful> list, string color)
{
    List<IColorful> result = list.Where(item => item.Color == color).ToList();
    return result;
}

这样称呼它:

var entities = FindByColor(_Entities.Cars, color);
entities.AddRange(FindByColor(_Entities.Bikes, color))

首先要么定义它们都派生自的基 class,要么定义它们都实现的接口。我将从这里假设他们实现了一个 IColoured 接口和 Colour 属性。 (虽然我会注意到在成员名称中使用 en-US 很常见,因此颜色由 Color 属性 表示)。

所以,假设您的汽车 class 是由 EF 创建的:

namespace SomeNamespace
{
  public partial class Cars
  {
    /*…*/
    public string Colour { get; set; }
    /*…*/
  }
}

然后你可以有一个文件:

namespace SomeNamespace
{
  public partial class Cars : IColoured
  {
  }
}

因为在编译 class 定义时将两个 partial 代码组合在一起,您的代码只需要指示接口已实现,匹配 属性 的事实在另一个文件无关紧要。

然后:

public static IQueryable<T> FilterByColour<T>(this IQueryable<T> source, string colour)
  where T : IColoured
{
  return source.Where(p => p.Colour == colour);
}

现在您可以使用 _Entities.Cars.FilterByColour("white")_Entities.Bikes.FilterByColour("blue") 等。如果按 "white" 过滤是一种特别常见的情况,那么:

重要提示:如果您没有充分的理由(例如使用不是与 EF 兼容),请使用 IQueryable<>,以便它仍由 EF 处理,并且可以在数据库上进行过滤,而不是从数据库中检索所有内容并在您的应用程序中进行过滤。

public static IQueryable<T> FilterWhite<T>(this IQueryable<T> source)
  where T : IColoured
{
  return source.FilterByColour("white");
}

或者,如果 FilterByColour 没有其他用途,那么:

public static IQueryable<T> FilterWhite<T>(this IQueryable<T> source)
  where T : IColoured
{
  return source.Where(p => p.Colour == "white");
}

会起作用。