2010-07-06 53 views
2

我正在寻找一种方式来公开通过WCF数据服务我现有的业务层的一个子集(这是基于LinqToSql),以便通过WCF数据服务公开LinqToSQL业务层

  1. 数据服务由于我的业务层随着时间的推移而发生变化,仍然可以由旧的odata客户端使用(读取和写入)。看来唯一的方法就是确保数据服务不会改变,即使业务层发生了变化。

  2. 我的业务对象的一些属性是隐藏的。

  3. 的数据服务可以处理比较大(数以万计的企业实体)数据库

  4. 它并不需要我几个星期来实现数据服务

我已经试过了几不同的方法,但他们每个人都有相当大的缺点。任何指导我忽视的东西将不胜感激。

这是到目前为止,我已经试过的方法:

第一种方法:基于反射提供商实现IUpdateable,业务对象实现一个定义良好的接口

而不是暴露我的LinqToSQL直接对象,我试图让他们实现一个接口,该接口定义了我想要公开的属性并仅公开该数据服务上的接口。例如,如果我有一个客户LINQ的实体,我把它实现的ICustomer接口:

public interface ICustomer{ 
    int ID{get;set;} 
    string Name{get;set;} 
} 


//My Linq entity 
public partial class Customer: ICustomer{ 
    public int ID{get;set;} 
    public string Name{get;set;} 
    public string SomeOtherPropertyIDoNotWantToExpose{get;set;} 
} 

然后在我的数据服务提供者,我只是把房地产像

public IQueryable<ICustomer> Customers { 
     get { 
     //Note that the method below returns an IQueryable<Customer> 
     return MyBusinessLayerCustomersProvider.LoadAllCustomers(); 
     } 
    } 

可惜,这是行不通的。当试图从客户端访问数据服务并使用任何依赖于OrderBy的Linq方法(如myContext.Customers.First())时,出现以下错误:

没有泛型方法'OrderBy' System.Linq.Queryable'与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。

我不知道为什么发生这种情况,但我坚持在这一点。

方法二:基于反射提供商实现IUpdateable,包装类在我exising实体

在这种情况下,我试图实现类在我的LINQ实体和数据服务暴露包装类。喜欢的东西:

//My Linq entity 
    public partial class Customer 
    { 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public string SomeOtherPropertyIDoNotWantToExpose { get; set; } 
    } 

    //the wrapper 
    public partial class WrappedCustomer 
    { 
    internal Customer _wrappedEntity; 
    public int ID { get{ return _wrappedEntity.ID;} set{ _wrappedEntity.ID = value;} } 
    public string Name { get { return _wrappedEntity.Name; } set { _wrappedEntity.Name = value; } } 
    } 

这种方法的问题是,这是行不通的,除非我加载所有客户实体从我的数据库中存储的每个请求的数据服务。这是因为在该客户财产上的数据服务提供商的样子:

public IQueryable<Customer> WrappedCustomer 
{ 
    get 
    { 
    IQueryable<WrappedCustomer> customers = from c in MyBusinessLayerCustomersProvider.LoadAllCustomers 
       select new WrappedCustomer{_wrappedEntity = c}; 

    //I am casting to list to avoid "no supported translation to sql" errors. 
    return tasks.ToList().AsQueryable(); 
    } 
} 

所以即使我的WCF数据服务的页面大小限制为100,上面的代码将之前加载所有客户的实体内存可以找到客户实际想要加载的适当实体。所以这似乎没有适当的比例。

第三条道路:直接暴露LinqToSQL实体,使用IgnoreProperties属性

在这种情况下,我有我的数据服务回报从我的业务层直接发起linqtosql实体和使用IgnoreProperties属性隐藏属性我不想在数据层中公开。此方法可扩展且易于实现,但不支持正确版本化数据服务。例如,如果我想实现我的数据服务的第2版,那么可能需要隐藏比第一个服务中更少的linq实体属性。并且似乎没有办法在单个LinqToSQL实体上使用多个IgnoreProperties属性。

第四种方法:实现自定义数据服务提供商

看来,自定义数据服务提供商可以很容易地覆盖所有的我的要求。现在可能只是我,但这看起来太复杂了。看来我必须实现IDataServiceMetadataProvider,IDataServiceQueryProvider,IDataServiceUpdateProvider和IServiceProvider,这些都不重要。即使在阅读Alex J's article series关于此主题并查看了odata网站上提供的示例之后,我仍然没有得到实际需要实现的大部分功能。

实现IUpdateable似乎要复杂得多,特别是因为我不知道样本中提供的哪些代码部分可以简单地复制粘贴或需要定制。

第五种方法:使用EF并找到了一些方法,使既LINQ to SQL和EF

业务层的工作,我成功地实施了概念本的证明,但它是相当混乱的,所以我'd只能用这个作为最后的手段。

那么,我忽略了什么?接下来我应该做什么?我没有时间了,所以任何建议将不胜感激。

感谢,

阿德里安

回答

1

看来,覆盖所有的我的要求的唯一办法是实现一个自定义数据服务提供商(see this thread)。这不是一个小任务,所以我决定现在使用反射提供程序+ IUpdateable实现,并在稍后出现需求(由于版本问题)时实现自定义数据服务提供程序。