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

Posted

技术标签:

【中文标题】使用 linq to sql 后端通过 WCF 查询 DTO 对象【英文标题】:Query DTO objects through WCF with linq to sql backend 【发布时间】:2012-04-06 01:58:37 【问题描述】:

我正在开展一个项目,我们需要针对该项目创建复杂的查询 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 让我很容易绑定到 L2S-datacontext,它公开了我的数据模型而不是 DTO。

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

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

【问题讨论】:

【参考方案1】:

使用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 服务,它们实际上非常非常强大。

【讨论】:

这听起来像是一个很好的解决方案,但我无法让它发挥作用。我怀疑这与我使用 L2S 而不是 EF 的事实有关 发现至少两个问题。我不能使用辅助方法,并且由于上下文包含在使用中,因此将在查询集合时释放它。 使用 L2S 或 EF 没关系。您可以汇集来自任何来源的数据。由于 OData 服务对象是“按请求”创建的,因此使用 using 语句是正确的方法,因为 DataModel 类实例将随请求一起创建和销毁。 我不同意 using 语句,一旦 datacontext 超出范围,即在调用 Get() 之前,将调用 dispose 方法。【参考方案2】:

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

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

这是你要找的东西吗?

【讨论】:

【参考方案3】:

如果您有很长的复杂实体,那么手动创建投影就是一场噩梦。 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 - 所以现在可能包含它的一些改进版本。总体概念似乎很棒,这个版本对我来说效果很好。

【讨论】:

以上是关于使用 linq to sql 后端通过 WCF 查询 DTO 对象的主要内容,如果未能解决你的问题,请参考以下文章

在数据访问应用程序块之上使用“LINQ to SQL”和“WCF 数据服务”

为啥,当我在 WCF 服务中模拟时,当我尝试运行 LINQ to SQL 查询时,我的服务不能加载 System.Transactions?

关于将 Flex 与 WCF 和 Linq to Entities 一起使用的建议

Linq to SQL 的增删改查操作

LinQ to Sql中的增删改查

利用LINQ to SQL 增删改查本地数据库