2012-03-21 70 views
1

我正在一个项目,我们需要创建一个WCF服务 复杂查询。查询DTO对象通过WCF与LINQ到SQL后端

该服务使用LINQ在后端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类的映射。

回答

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

+0

这听起来像一个很好的解决方案,但我不能得到它的工作。我怀疑它与我使用L2S而不是EF – 2012-03-21 15:22:22

+0

的事实有关,发现至少有两个问题。我无法使用帮助器方法,并且由于上下文被封装在使用中,因此将在查询集合时处理它。 – 2012-03-21 16:01:32

+0

使用L2S或EF无关紧要。您可以汇集来自任何来源的数据。由于OData服务对象是按照“每个请求”创建的,所以使用'using'语句是正确的方式,因为DataModel类实例将随请求一起创建和销毁。 – 2012-03-21 16:49:46

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--所以现在可能包含一些改进版本。一般的概念似乎很棒,这个版本对我来说效果很好。