C# 同时编码SQL投影和映射?

C# 同时编码SQL投影和映射?,c#,entity-framework-6,C#,Entity Framework 6,这可以从数据库中的地址对象中分割出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到ViewMod

这可以从数据库中的地址对象中分割出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();
MyCustomMapper.Map<Entity, ViewModel>(entity);
但是SQL不能使用构造函数。上面的对象初始值设定项不使用函数映射字段。当然可以。AsEnumerable.Select q=>new DDLq,但这会选择SQL中包括数据在内的所有字段,将其发送到C,然后C会分割出我们需要的字段,以传输我们不需要的数据


有什么建议吗?我们碰巧使用实体框架6来提取数据。

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

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

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

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

你反对使用第三方库吗?Automapper's做的正是你想要的

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

你反对使用第三方库吗?Automapper's做的正是你想要的

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);
我自己做了一个小静态映射器,保存所有的地图并为我使用它们。在我的所有ViewModels中,贴图都是在静态初始值设定项中声明的。结果让我感觉像AutoMapper,但不需要lib或复杂的映射代码,也不会为您带来任何魔力

我可以这样写:

List<DDL> mylist = Addresses
    .Select( q => new DDL(q))  // <-- constructor maps POCO to VM
    .ToList();
MyCustomMapper.Map<Entity, ViewModel>(entity);

而且它被重载以接受IEnumerables、IQueryables和单个ViewModel。我还添加了只有1个泛型类型的重载,即接受类型参数的实体。这是我的一个要求。

您所需要的就是在某个地方定义表达式并使用它。例如,在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);
我自己做了一个小静态映射器,保存所有的地图并为我使用它们。在我的所有ViewModels中,贴图都是在静态初始值设定项中声明的。结果让我感觉像AutoMapper,但不需要lib或复杂的映射代码,也不会为您带来任何魔力

我可以这样写:

List<DDL> mylist = Addresses
    .Select( q => new DDL(q))  // <-- constructor maps POCO to VM
    .ToList();
MyCustomMapper.Map<Entity, ViewModel>(entity);

而且它被重载以接受IEnumerables、IQueryables和单个ViewModel。我还添加了只有1个泛型类型的重载,即接受类型参数的实体。这是我的一项要求。

看看这个看看这个你最好还是坚持OP的建议,即一个可数的数组,而不是一个数组-这将为你节省创建数组的费用。不客气-我应该提到,如果你这样做,SQL调用实际上是在调用ToList时执行的-AsEnumerable调用的效果是导致Select扩展方法解析为Enumerable.Select而不是Queryable.Select;它不会强制执行查询。当然,在一个单独的表达式中,这并没有多大关系,但如果将它分解为多个表达式,它可能会变得有意义。还有你的,;位于错误的位置。如果AsEnumerable未查询数据库,则第二个select将引发异常,无论您使用哪个扩展名Enumerable或Queryable。EF无法将带参数的构造函数转换为SQL查询。@我同意,这也是我最初使用的原因。ToArray用于提取数据…现在无法测试它,我在这一点上信任phoog:@ibiza这不是一个坏主意,但这基本上就是第一个示例所做的。你最好还是坚持OP的建议,即一个可数数组,而不是数组-这将节省你创建数组的费用。不客气-我应该提到,如果你这样做,SQL调用实际上是在调用ToList时执行的-AsEnumerable调用的效果是导致Select扩展方法解析为Enumerable.Select而不是Queryable.Select;它不会强制执行查询。当然,在一个单独的表达式中,这并没有多大关系,但如果将它分解为多个表达式,它可能会变得有意义。还有你的,;位于错误的位置。如果AsEnumerable未查询数据库,则第二个select将引发异常,无论您使用哪个扩展名Enumerable或Queryable。EF无法将带参数的构造函数转换为SQL查询。@我同意,这也是我最初使用的原因。ToArray用于提取数据…现在无法测试它,我相信phoog的说法:@ibiza这不是一个坏主意,但基本上是第一个示例所做的。那么呢?@Dr.Zim是的,如果你是
实际上,阅读他们谈论的文章时,你应该使用他的address.Project.To方法,而不是Mapper.MapAddresses。该代码以automapper.QueryableExtensions名称空间的形式集成到主automapper项目中,而不是单独下载。@Dr.Zim您是否打算将这些评论发布在上而不是我的上?如果你把它们贴在那里会有意义的,例如,为什么你说的和斯科特的一样好?你打字比我快。哈哈。如果你使用AutoMapper,你的答案肯定是最好的。那怎么办?@Dr.Zim是的,如果你真的读了他们谈论的文章,你应该使用他的Addresses.Project.To方法,而不是Mapper.MapAddresses。该代码以automapper.QueryableExtensions名称空间的形式集成到主automapper项目中,而不是单独下载。@Dr.Zim您是否打算将这些评论发布在上而不是我的上?如果你把它们贴在那里会有意义的,例如,为什么你说的和斯科特的一样好?你打字比我快。哈哈。如果你使用AutoMapper,你的答案肯定是最好的。我从来没有想到空间是移动的东西!不要在IQueryable对象上使用Mapper.Map,您需要使用Automapper.QueryableExtensions命名空间。如果使用Mapper.Map,将得到非常糟糕的SQL查询。有关Automapper作者解释可查询扩展的消息,请参阅。@ScottChamberlain我在哪里说过我在使用Automapper?@Dr.Zim很抱歉,但我必须用谷歌搜索报价才能知道它是什么。我不是星际迷航迷:@Pluc我可以写这样的东西:Mapper.mapeentity;而且它被重载以接受IEnumerables、IQueryables和单个ViewModel。它不会重载以接受IQueryables,IQueryable是从IEnumerable派生的,因此它接受作为可枚举的queryable,但您不会得到任何优化。如果您使用Mapper.Map,它将始终查询查询中所有包含表的所有列,而不仅仅是使用.Project.To时所需的列。我从未想到空间是移动的对象!不要在IQueryable对象上使用Mapper.Map,您需要使用Automapper.QueryableExtensions命名空间。如果使用Mapper.Map,将得到非常糟糕的SQL查询。有关Automapper作者解释可查询扩展的消息,请参阅。@ScottChamberlain我在哪里说过我在使用Automapper?@Dr.Zim很抱歉,但我必须用谷歌搜索报价才能知道它是什么。我不是星际迷航迷:@Pluc我可以写这样的东西:Mapper.mapeentity;而且它被重载以接受IEnumerables、IQueryables和单个ViewModel。它不会重载以接受IQueryables,IQueryable是从IEnumerable派生的,因此它接受作为可枚举的queryable,但您不会得到任何优化。如果使用Mapper.Map,它将始终查询查询中包含的所有表的所有列,而不仅仅是使用.Project.To时所需的列。