这可以从我们数据库的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来提取数据。
答案 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();