同时编写SQL投影和映射?

时间:2015-04-02 17:03:04

标签: c# entity-framework-6

这可以从我们数据库的Address对象中创建一个DDL对象:

public class DDL {
    public int?   id   { get; set; }
    public string name { get; set; }
}

List<DDL> mylist = Addresses
    .Select( q => new DDL { id = q.id, name = q.name })
    .ToList();

但是,我们希望将我们的POCO保留在我们的MVC控制器代码之外的单个位置的ViewModel映射中。我们想做这样的事情:

List<DDL> mylist = Addresses
    .Select( q => new DDL(q))  // <-- constructor maps POCO to VM
    .ToList();

但是SQL不能使用构造函数。上面的对象初始化程序不使用函数来映射字段。当然你可以做.AsEnumerable().Select( q => new DDL(q)),但这会选择SQL中的所有字段(包括数据),将其发送到C#,然后C#将我们需要的字段划分出来(传输数据非常低效,我们不会这样做所需要的。)

有什么建议吗?我们碰巧使用Entity Framework 6来提取数据。

3 个答案:

答案 0 :(得分:2)

您可以使用匿名类型来限制从数据库中选择的内容,然后使用这些字段构建您的对象:

List<DDL> mylist = Addresses
    .Select( q => new { id, name })
    .AsEnumerable()
    .Select(i => new DDL(i.id, i.name) // <- On the Enumerable and not on the Queryable
    .ToList();

答案 1 :(得分:2)

您只需要在某处定义表达式并使用它。例如,在ViewModel中作为静态只读字段。

public class SomeViewModel
{
    public static readonly Expression<Func<SomeEntity, SomeViewModel>> Map = (o) => new SomeViewModel
    {
        id = o.id,
        name = o.name
    }

    public int id { get; set; }
    public string name { get; set; }
}

// Somewhere in your controller
var mappedAddresses = Addresses.Select(SomeViewModel.Map);

我亲自制作了一个静态Mapper,它可以保存所有地图并将它们用于我。地图在我的所有ViewModel中的静态初始化程序中声明。结果给了我一些感觉像AutoMapper的东西,但不需要lib或复杂的映射代码(但也不会为你做任何魔术)。

我可以这样写:

MyCustomMapper.Map<Entity, ViewModel>(entity);

并且重载以接受IEnumerables,IQueryables和单个ViewModel。我还添加了只有1个接受类型参数的泛型类型(实体)的重载。这是我的要求。

答案 2 :(得分:1)

您反对使用第三方库吗? Automapper的QueryableExtensions完全符合您的要求。

List<DDL> mylist = Addresses
    .Project().To<DDL>()
    .ToList();

它甚至具有很好的功能,例如能够对转换后的对象进行过滤以及在服务器端执行过滤器。

List<DDL> mylist = Addresses
    .Project().To<DDL>()
    .Where(d => d.name = "Smith") //This gets translated to SQL even though it was performed on DDL.
    .ToList();