同时编写一个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 个接受类型参数的泛型类型(实体)的重载。这是对我的要求。
这可以从我们数据库的地址对象中分离出一个 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 个接受类型参数的泛型类型(实体)的重载。这是对我的要求。