实体框架查询中的可重用逻辑

时间:2015-12-21 20:00:07

标签: c# entity-framework linq-to-entities entity-framework-6

假设我有以下内容(用于在下拉列表中显示项目):

class SelectItemViewModel<TId>
{
  string Name {get; set;}
  TId Id {get; set;}
}

以及我的数据库实体:

interface IEntity<TId>
{
  TId Id {get;
}

我希望能够重用逻辑来创建这些下拉项,并传递一些名称。例如,我现在(简化):

List<SelectItemViewModel<int>> GetAvailableEntity1Items(IQuerable<Entity1> entities)
{
  return entities
    .Select(e => new SelectItemViewModel<int>
    {
      Id = e.Id,
      Name = e.Title
    })
    .ToList();
}


List<SelectItemViewModel<short>> GetAvailableEntity2Items(IQuerable<Entity2> entities)
{
  return entities
    .Select(e => new SelectItemViewModel<short>
    {
      Id = e.Id,
      Name = e.Description
    })
    .ToList();
}

他们显然具有相同的基本结构。我想对IEntity<T>进行操作并传入“获取名称”功能,但我无法使用Entity Framework。

不起作用:

List<SelectItemViewModel<TId> GetAvailableItems<TEntity, TId>(IQueryable<TEntity> entitiesQuery, Func<TEntity, string> getNameForEntity)
  where TEntity : class, IEntity<TId>
{
  return entitiesQuery
    .Select(e => new SelectItemViewModel<TId>
    {
      Id = e.Id,
      Name = getNameForEntity(e)
    }
}

我无法弄清楚我是如何实施的

List<SelectItemViewModel<TId> GetAvailableItems<TEntity, TId>(IQueryable<TEntity> entitiesQuery, Expression<Func<TEntity, string>> getNameForEntity)
  where TEntity : class, IEntity<TId>
{
  return entitiesQuery
    .Select(e => new SelectItemViewModel<TId>
    {
      Id = e.Id,
      Name = ??
    }
}

有没有办法在这里重用逻辑?我能想到的另一件事是另一个界面,例如IHasName获取名称,但坦率地说,我不希望数据库实体负责指明它们应如何在UI层中显示。

2 个答案:

答案 0 :(得分:1)

另一种方法是从数据库中检索整个实体,然后将其转换为SelectItemViewModel:

List<SelectItemViewModel<TId> GetAvailableItems<TEntity, TId>(IQueryable<TEntity> entitiesQuery, Func<TEntity, string> getNameForEntity)
  where TEntity : class, IEntity<TId>
{
  return entitiesQuery
    .AsEnumerable() 
    .Select(e => new SelectItemViewModel<TId>
    {
      Id = e.Id,
      Name = getNameForEntity(e)
    }
}

答案 1 :(得分:1)

  

我无法弄清楚我是如何实施的

欢迎来到System.Linq.Expressions。像这样的事情应该做的工作

List<SelectItemViewModel<TId>> GetAvailableItems<TEntity, TId>(IQueryable<TEntity> source, Expression<Func<TEntity, string>> nameSelector)
    where TEntity : class, IEntity<TId>
{
    var item = nameSelector.Parameters[0];
    var targetType = typeof(SelectItemViewModel<TId>);
    var selector = Expression.Lambda<Func<TEntity, SelectItemViewModel<TId>>>( 
        Expression.MemberInit(Expression.New(targetType),
            Expression.Bind(targetType.GetProperty("Name"), nameSelector.Body),
            Expression.Bind(targetType.GetProperty("Id"), Expression.Property(item, "Id"))
        ), item);
    return source.Select(selector).ToList();

}