我正在开发一个 Silverlight 应用程序,它从 WCF 数据服务中提取数据,但是与该服务的通信位于外观后面。我这样做是为了在尚未实现服务器的情况下促进 SL 应用程序的开发,因此 SL 应用程序可以使用 txt 文件中的数据并且不知道其中的区别。
下面的接口构成了门面,具体的类是它们在门面后面的实现。
public interface IDataContext
{
    IEntityQuery<IRootEntity> Roots { get; }
    IEntityQuery<IBranchEntity> Branches{ get; }
    IEntityQuery<ILeafEntity> Leaves { get; }
}
public interface IEntityQuery<TEntity> : IQueryable<TModel>
{
    IAsyncResult BeginExecute(AsyncCallback callback, object state);
    IEnumerable<TModel> EndExecute(IAsyncResult asyncResult);
    IEntityQuery<TModel> Where(Expression<Func<TModel, bool>> predicate);
}
public interface IEntityCollection<TEntity> : INotifyCollectionChanged,
    INotifyPropertyChanged, IQueryable<TModel>
{
}
public interface IRootEntity
{
    int Id { get; set; }
    string Name { get; set; }
    IModelCollection<IBranchEntity> Branches { get; set; }
}
public interface IBranchEntity
{
    int Id { get; set; }
    string Name { get; set; }
    IRootEntity Root { get; set; }
    IModelCollection<ILeafEntity> Leaves { get; set; }
}
public interface ILeafEntity
{
    int Id { get; set; }
    string Name { get; set; }
    IBranchEntity Branch { get; set; }
}
// Partially implemented by me and partially by Visual Studio when the Service
// Reference was added.
public partial class Container : IDataContext
{
    IEntityQuery<IRootEntity> IDataContext.Roots 
    { 
        get 
        { 
            return new ModelQuery<IRootEntity, RootEntity>(this.Roots); 
        }
    }
    IEntityQuery<IBranchEntity> IDataContext.Branches
    { 
        get 
        { 
            return new ModelQuery<IBranchEntity, BranchEntity>(this.Roots); 
        }
    }
    IEntityQuery<ILeafEntity> IDataContext.Leaves
    { 
        get 
        { 
            return new ModelQuery<ILeafEntity, LeafEntity>(this.Leaves); 
        }
    }
}
public class EntityQuery<TFacade, TConcrete>
    where TConcrete : class, TFacade
{
    private DataServiceQuery<TConcrete> _dsq;
    public ModelQuery(DataServiceQuery<TConcrete> dsq)
    {
        _dsq = dsq;
    }
    public IAsyncResult BeginExecute(AsyncCallback callback, object state)
    {
        return _dsq.BeginExecute(callback, state);
    }
    public IEnumerable<TFacade> EndExecute(IAsyncResult asyncResult)
    {
        return _dsq.EndExecute(asyncResult).AsEnumerable() as IEnumerable<TFacade>;
    }
    public IModelQuery<TFacade> Where(Expression<Func<TFacade, bool>> predicate)
    {
        Expression<Func<TConcrete, bool>> concretePredicate = Expression.Lambda<Func<TConcrete, bool>>(predicate.Body, predicate.Parameters);
        return new ModelQuery<TFacade, TConcrete>(_dsq.Where(concretePredicate) as DataServiceQuery<TConcrete>);
    }
    // IQueryable implementation ...
}
public class EntityCollection<TFacade, TConcrete> : IEntityCollection<TFacade>
    where TConcrete : class, TFacade
{
    public EntityCollection(ObservableCollection<TConcrete> innerCollection)
    {
        this.InnerCollection = innerCollection;
        this.InnerCollection.CollectionChanged += InnerCollection_CollectionChanged;
    }
    internal ObservableCollection<TConcrete> InnerCollection { get; private set; }
    private void InnerCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        this.OnCollectionChanged(e);
    }
    // IQueryable<TFacade> implementation ...
}
// Partially implemented by me and partially by Visual Studio when the Service
// Reference was added.
public partial class RootEntity : IRootEntity
{   
    IList<IBranchEntity> IRootEntity.Branches
    {
        get { return this.Branches; }
        set { this.Branches = value as IList<IBranchEntity>; }
    }
}
// Partially implemented by me and partially by Visual Studio when the Service
// Reference was added.
public partial class BranchEntity : IBranchEntity 
{   
    IRootEntity IBranchEntity.Root
    {
        get { return this.Root; }
        set { this.Root = value as RootEntity; }
    }
    IList<ILeafEntity> IBranchEntity.Leaves
    {
        get { return this.Leaves; }
        set { this.Leaves = value as IList<LeafEntity>; }
    }
}
// Partially implemented by me and partially by Visual Studio when the Service
// Reference was added.
public partial class LeafEntity : ILeafEntity 
{   
    IRootEntity ILeafEntity.Root
    {
        get { return this.Root; }
        set { this.Root = value as RootEntity; }
    }
}
EntityQuery和EntityCollection类成为维护外观抽象所必需的。没有它们,SL 应用程序将不得不知道DataServiceQuery和DataServiceCollection.
我遇到的问题是将 SL 应用程序开发人员针对外观编写的 LINQ 查询转换为客户端 WCF 数据服务代理可以转换为 OData URL 的 LINQ 查询。
我已经能够运行一些简单的查询,但更复杂的查询开始抛出异常。当前给我带来问题的查询如下:
IEntityQuery<IRootEntity> query = this.Context.Roots
    .Where(r => r.Branches.Any(b=> b.Leaves.Any(l => l.Name == "Find Me")));
IRootEntity result = Task.Factory.StartNew(() => query.BeginExecute(null, null))
    .ContinueWith(t => query.EndExecute(t.Result))
    .Result
    .Single();
我收到一条NotSupportedException说明“'Any' 方法的源参数必须是导航或集合属性。” 我很确定这是因为Any()正在调用 aModelCollection<T1,T2>而不是DataServiceCollection<T>它的 InnerCollection,但我不知道该怎么做。