1

我有一个数据库和一个映射到它的实体框架模型。该数据库有一个包含许多列的“产品”表。在许多 EF 查询中,我只需要几列,我做一个投影,比方说

var projected = Context.Products
    .Select(p => new ProjectedProduct { ProdID = p.ID, ProdTitle = p.Title })
    .ToArray();

由于此投影被多次使用,我将其移至单独的方法:

public static IQueryable<ProjectedProduct> ToProjectedProduct(this IQueryable<Product> query)
{
    return query.Select(p => 
        new ProjectedProduct { ProdID = p.ID, ProdTitle = p.Title });
}

所以我可以使用如下投影:

var projected = Context.Products.ToProjectedProduct().ToArray();

现在我还想对单个产品实例使用相同的投影,例如:

var prod = Context.Products.First(p => p);
var projected = new ProjectedProduct { ProdID = prod.ID, ProdTitle = prod.Title });

而且我仍然想对投影使用相同的辅助方法,以便将它放在一个地方,但它不起作用,因为它仅适用于 IQueryable。我能做的是将投影转换为另一种方法,例如

public static ProjectedProduct ToProjectedProduct(this Product p)
{
    return new ProjectedProduct { ProdID = p.ID, ProdTitle = p.Title });
}

但现在这种方法不适用于 IQueryable。我需要一个适用于这两种情况的辅助方法,我想做的是:

var projected = Context.Products.Select(p => p.ToProjectedProduct()).ToArray();

但这不起作用,因为辅助方法无法转换为数据库查询。

4

2 回答 2

1

为此使用Automapper 。使用 Automapper,您可以:

Mapper.CreateMap<Product, ProjectedProduct>
    .ForMember(dto => dto.ProdID, m => m.MapFrom(p => p.ID))
    .ForMember(dto => dto.ProdTitle , m => m.MapFrom(p => p.Title));

ForMember指定不同名称的属性之间的映射,Automapper 自动映射具有相同名称的属性)。

现在您定义了一个可重用的投影。

稍后您可以执行以下操作:

var projected = Context.Products.Project().To<ProjectedProduct>().ToArray();

Automapper 被广泛使用,您会发现许多如何使用它的示例。

于 2013-04-02T23:05:42.413 回答
0

IQueryable 的选择扩展方法需要一个Expression<Func<TSource, TResult>>. 这意味着我们可以在其他地方定义一个与此参数匹配的对象并将其传递给我们的 select 语句。

属性(也可以是方法):

public Expression<Func<Product, ProjectedProduct>> MapProduct
{
    get
    {
        return p => new ProjectedProduct { ProdID = p.ID, ProdTitle = p.Title };
    }
}

可查询的用法:

var projected = Context.Products
    .Select(MapProduct)
    .ToArray();

单实例用法:

var projected = Context.Products.Select(MapProduct).First();

IEnumerable 用法:

// calling compile turns the expression into a normal Func
var projected = ProductList.Select(MapProduct.Compile());

正常对象用法:

var projected = MapProduct.Compile()(ProdObj);

MSDN IQueryable.Select - http://msdn.microsoft.com/en-us/library/bb534638(v=vs.100).aspx

于 2013-04-02T23:15:02.433 回答