2014-11-21 63 views
0

我认为必须提出同样的问题,但我不知道如何正确描述它。如何将查询结果中的对象转换为自定义类型

我使用实体框架,我有一个叫做供应商的表,由许多列:

[vendor] 
- [Id] [INT] 
- [Name] [NVARCHAR] 
- [ApiUrl] [NVARCHAR] 
- ... 

我写一个Web API来公开哪些用户可以通过获取供应商记录的功能。但是,我只想提供三列。

所以我创建了一个模型类,如下:

public class OM_Vendor 
{ 
    public int Id { set; get; } 
    public string Name { set; get; } 
    public string ApiUrl { set; get; } 
} 

与EF建立模型类之后,EF的上下文对象有一个现在被命名为供应商属性。然后,在API控制器,I编码是这样的:

var vendors = this.objEntity.vendors 
.Where<OM_Vendor>(v => v.Status == "1") 
.OrderBy(v => v.Id) 
.Skip(intSkip) 
.Take(intLimit) 
.ToList(); 

它不工作,也不做这个的:

var vendors = this.objEntity.vendors 
.Where(v => v.Status == "1") 
.OrderBy(v => v.Id) 
.Skip(intSkip) 
.Take(intLimit) 
.ToList<OM_Vendor>(); 

有没有办法通过类似上面的方法返回的对象转换我的自定义类型?

非常感谢。


另外,我知道我能得到它以这种方式工作:

var vendors = new List<OM_Vendor>(); 
vendors = objCont.ExecuteStoreQuery<OM_Vendor>("SELECT * FROM vendor").ToList(); 

而且这种方式也工作:

var vendors = this.objCont.vendors 
       .Where(v => v.Status == "1") 
       .OrderBy(v => v.Id) 
       .Select(
        row => new 
         { 
          Id= row.Id, 
          Name = row.Name, 
          ApiUrl = row.ApiUrl 
         } 
       ) 
       .Skip(intSkip) 
       .Take(intLimit) 
       .ToList(); 

更新:

根据@安德鲁的回答,我更新了我的鳕鱼Ë如下:

public class OM_Vendor 
{ 
    public int Id { set; get; } 
    public string Name { set; get; } 
    public string ApiUrl { set; get; } 

    public static implicit operator OM_Vendor(vendor vendor){ 
     return new OM_Vendor 
     { 
      Id = vendor.Id, 
      Name = vendor.Name, 
      ApiUrl = vendor.ApiUrl 
     }; 
    } 
} 

在我的控制器类:

List<OM_Vendor> vendors = this.objCont.vendors 
             .Where(v => v.Status == "1") 
             .OrderBy(v => v.Id) 
             .Skip(intSkip) 
             .Take(intLimit) 
             .ToList(); 

我得到了错误,说:

无法隐式转换类型 'System.Collections.Generic.List' 来 'System.Collections.Generic.List'

我错过了什么?至于显式演员,我将不得不在每个循环中显式地转换每个实例?

+0

所以使用投影有什么问题?好像你问是否有不同的方式来完成这一点,因为你说它的工作方式...... – Claies 2014-11-21 04:20:12

+0

我的问题是,我可以做投影而不执行SQL语句吗?只需使用我的自定义类型OM_Vendor从供应商集合直接进行投影即可。 – VincentZHANG 2014-11-21 06:08:44

回答

2

你基本上有3种方法来实现你想实现什么。

  1. 使用.Select() linq扩展方法创建一个投影(如上例所示)。)通常一个好的选项,因为这将创建一个SQL表达式,它只返回数据传输对象所需的字段。
  2. 创建自定义投射运算符,例如public static implicit Operator OM_Vendor(Vendor vendor),其中包含完整的Vendor对象并将其分配给OM_Vendor的实例。这里的主要缺点是,你基本上是通过实体框架检索所有字段,只是为了在隐式转换过程中展开实体并丢弃其中的许多字段。
  3. 使用自定义库(如Automapper)来自动执行转换对象的过程。遇到大多数与2.相同的问题,但如果您有许多正在展平的类,那么让它由图书馆处理可能会有所帮助。

更完整的代码示例演示:

public class OM_Vendor { 
    ... 
    public static implicit Operator OM_Vendor(Vendor vendor){ 
     return new OM_Vendor { 
      Id = vendor.Id; 
      Name = vendor.Name; 
      ApiUrl = vendor.ApiUrl; 
    } 
} 

OM_Vendor om_Vendor = this.objEntity.vendors.Where(
... 

List<OM_Vendor> vendors = this.objEntity.vendors.Where(
... 

无论这些语句应该正确地执行,以一个OM_Vendor分配Vendor实例时使用implicit Operator作为构造。但是,它不能被夸大,这是在代码级别展开对象,并且会导致大于必需的SQL查询。

这实际上应该是显式运算符,因为在转换过程中会发生数据丢失。将implicit Operator更改为explicit Operator将导致此转换需要转换,即OM_Vendor omVendor = (OM_Vendor)vendor;。这使得转换更加清晰,但使代码略为冗长。

+0

你最终选择了哪条路线? – Claies 2014-11-24 01:43:55

+0

谢谢安德鲁,您的全面解答。但是我没有编译它;我更新了这篇文章,添加了我的新代码。你会看看,非常感谢。 – VincentZHANG 2014-11-24 02:23:48

+0

我正在查看代码和现在的错误...我不确定它为什么要尝试转换为通用列表而不是打印的列表,但我确定这是我们可以设计出来的东西 – Claies 2014-11-24 02:26:28

0

您是否尝试过用投影:

.Select(row => new OM_Vendor{ Id=row.Id, Name=row.Name, ApiUrl=row.ApiUrl}) 
+0

呃纠正我,如果我错了,但没有必要如果你没有做一个聚合函数。而且,当你不提供选择时,它会自动选择所有。所以这不能成为它不适合他的原因。我不明白他为什么使用'this.objEntity',objEntity应该是EF模型的上下文实例。我认为这可能是他的问题。 – 2014-11-21 04:07:58

+0

@JordanM,谢谢。所显示的片段是从API控制器类复制的,并且我将objCont声明为该类的私有成员属性。我相信这与我的问题无关。嗯....我想是的。 – VincentZHANG 2014-11-21 06:05:15

相关问题