同时编写一个SQL投影和映射?

Code a SQL projection and mapping at the same time?

这可以从我们数据库的地址对象中分离出一个 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 到 ViewModel 的映射保存在 MVC 控制器代码之外的一个地方。我们想做这样的事情:

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 Framework6来拉取数据。

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

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();

您反对使用第 3 方库吗? 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();

您只需在某处定义表达式并使用它。例如,在您的 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);

我亲自为自己制作了一个静态的小映射器,它保留所有的地图并为我使用它们。在我所有的 ViewModel 中,这些映射都是在静态初始值设定项中声明的。结果给了我一些感觉像 AutoMapper,但不需要 lib 或复杂的映射代码(但也不会为你做任何魔术)。

我可以这样写:

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

它超载以接受 IEnumerables、IQueryables 和单个 ViewModel。我还添加了仅具有 1 个接受类型参数的泛型类型(实体)的重载。这是对我的要求。