使用linq-to-sql后端通过WCF查询DTO对象

本文关键字:查询 DTO 对象 WCF linq-to-sql 后端 使用 | 更新日期: 2023-09-27 18:28:36

我正在处理一个项目,在该项目中,我们需要针对WCF服务。

该服务在后端使用linq到sql,并将查询投影到数据传输对象,如下所示:

dbContext.GetQueryable().其中(x=>x.Id==formatId).Select(x=>FormatHelper.PopulateMSFormat(x)).ToList();

我想做的是在客户端指定一个查询,比如说,我想查询所有具有特定属性或其中几个属性的格式。这种风格的东西:

var assets=客户端。QueryForAssets()。其中(x=>(x.name=="Test"|| x=="Arne")&&x.doe=="john");

我知道我不能通过WCF返回IQueryable,但类似的事情可以通过OData服务完成。问题是我必须返回DTO,OData让我很容易地绑定到L2S数据上下文,它公开了我的数据模型,而不是DTO。

那么,有没有一种好的方法可以针对DTO序列化查询,从而有效地传播到l2s层?

我曾想过编写自己的查询语言,但我发现很难构建正确的表达式树作为l2s的谓词,因为没有从DTO到linq类的映射。

使用linq-to-sql后端通过WCF查询DTO对象

使用OData服务,您不必直接返回数据库实体。您可以简单地以可查询的格式返回任何DTO。然后,在LINQ的Select()方法的帮助下,您可以简单地在提供查询之前将任何数据库实体转换为DTO

public class DataModel
{
  public DataModel()
  {
    using (var dbContext = new DatabaseContext())
    {
      Employees = from e in dbContext.Employee
                  select new EmployeeDto
                  {
                    ID = e.EmployeeID,
                    DepartmentID = e.DepartmentID,
                    AddressID = e.AddressID,
                    FirstName = e.FirstName,
                    LastName = e.LastName,
                    StreetNumber = e.Address.StreetNumber,
                    StreetName = e.Address.StreetName
                  };
    }
  }
  /// <summary>Returns the list of employees.</summary>
  public IQueryable<EmployeeDto> Employees { get; private set; }
}

您现在可以很容易地将其设置为OData服务,如下所示:

public class EmployeeDataService : DataService<DataModel>

有关完整的实现细节,请参阅这篇关于该主题的优秀文章。一旦你掌握了OData服务,它们实际上是非常非常强大的。

我相信您可以通过使用OData服务来返回DTO。

看看http://www.codeproject.com/Articles/135490/Advanced-using-OData-in-NET-WCF-Data-Services.特别是"公开数据库的转换"部分。您可以将实体对象展开为DTO,并让客户端针对该DTO模型运行查询。

这是你要找的东西吗?

如果您有长期复杂的实体,那么手工创建投影就是一场噩梦。Automapper不起作用,因为LINQ无法将其与IQueryable结合使用。

这就是完美的解决方案:Stop using AutoMapper in your Data Access Code

它将"神奇地"为您生成一个投影,并使您能够基于DTO(数据传输对象)类运行oData查询。

    [Queryable]
    public IQueryable<DatabaseProductDTO> GetDatabaseProductDTO(ODataQueryOptions<DatabaseProductDTO> options)
    {
        // _db.DatabaseProducts is an EF table 
        // DatabaseProductDTO is my DTO object
        var projectedDTOs = _db.DatabaseProducts.Project().To<DatabaseProductDTO>();
        var settings = new ODataQuerySettings();
        var results = (IQueryable<DatabaseProductDTO>) options.ApplyTo(projectedDTOs, settings);
        return results.ToArray().AsQueryable();
    }

我用运行这个

/odata/DatabaseProductDTO?$filter=FreeShipping eq true

注意:这篇文章是几年前的文章,现在AutoMapper可能已经内置了这样的功能。我现在没有时间自己检查。上面引用的文章的灵感是基于AutoMapper作者自己的这篇文章——所以现在可能包含了它的一些改进版本。总体概念似乎很棒,这个版本对我来说运行得很好。