如何将查询结果中的对象转换为自定义类型

时间:2014-11-21 03:47:38

标签: c# asp.net linq entity-framework

我认为必须提出同样的问题,但我不知道如何正确描述。

我正在使用Entity Framework,我有一个名为vendor的表,包含许多列:

[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的上下文对象现在具有名为vendors的属性。然后,在API控制器中,我编码如下:

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

更新

根据@Andrew的回答,我更新了我的代码如下:

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

我得错误说:

  

无法隐式转换类型   &#39; System.Collections.Generic.List&#39;至   &#39; System.Collections.Generic.List&#39;

我错过了什么?至于显式转换,我将必须在循环中显式转换每个实例?

2 个答案:

答案 0 :(得分:2)

你基本上有3种方法来实现你想要完成的目标。

  1. 使用.Select() linq扩展方法创建投影(如上一个示例所示)。通常是一个不错的选项,因为这将创建一个只返回数据所需字段的SQL表达式转移对象。
  2. 创建自定义强制转换运算符,例如public static implicit Operator OM_Vendor(Vendor vendor),它接受​​一个完整的Vendor对象,并将其分配给OM_Vendor的实例。这里的主要缺点是您实际上是通过Entity Framework检索所有字段,只是为了在隐式转换期间展平实体并丢弃其中的许多字段。
  3. 使用Automapper等自定义库自动执行转换对象的过程。遇到与2.大多数相同的问题,但如果您有许多课程,那么由图书馆处理可能会有所帮助。
  4. 一个更完整的代码示例来演示:

    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(
    ...
    

    在将implicit Operator实例分配给Vendor时,使用OM_Vendor作为构造函数,这些语句中的任何一个都应该正确执行。但是,它不能被夸大,这是在代码级别展平对象,并将导致大于必要的SQL查询。

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

答案 1 :(得分:0)

您是否曾尝试投影:

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