我正在开发一个 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,但我不知道该怎么做。