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

时间:2012-03-21 14:21:15

标签: c# sql wcf linq dto

我正在开发一个需要创建复杂查询的项目 WCF服务。

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


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

我想要做的是在客户端指定查询,假设我想查询具有某个属性或其中几个属性的所有格式。 这种风格的东西:


     var assets = client.QueryForAssets().Where(x => (x.name == "Test" || x == "Arne") && x.doe ==  "john");

我知道我无法通过WCF返回IQueryable,但是可以使用OData服务完成类似的事情。问题是我必须返回DTO和OData让我很容易绑定到暴露我的数据模型而不是DTO的L2S-datacontext。

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

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

3 个答案:

答案 0 :(得分:2)

使用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>

有关完整实施的详细信息,see this有关此主题的优秀文章。一旦你掌握了它们,OData服务实际上非常强大。

答案 1 :(得分:0)

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

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

这是你要找的东西吗?

答案 2 :(得分:0)

如果你有很复杂的实体,那么手工制作投影就是一场噩梦。 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本身作者的this article - 因此现在可能包含一些改进版本。一般概念看起来很棒,这个版本对我来说效果很好。