共同投影?

时间:2013-04-02 22:29:45

标签: c# entity-framework-5 projection

我有一个数据库和一个映射到它的实体框架模型。该数据库有一个包含多列的“Products”表。在许多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();

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

2 个答案:

答案 0 :(得分: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被广泛使用,你会发现许多如何使用它的例子。

答案 1 :(得分:0)

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

属性(也可以是方法):

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

IQueryable用法:

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

单个实例用法:

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

IEnumerable usage:

// 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