• 自定义Data Service Providers —(6)查询


    完整教程目录请参见:《自定义Data Service Providers — 简介

    在上面的章节中,我们挂接了自定义的服务提供者,并且实现了IDataServiceQueryProvider接口,虽然他只能用来查询元数据和服务契约。

    在这一部分,我们让查询也可以运行起来,要做到这点我们必须知道数据从哪里来:数据源,以及我们必须实现IDataServiceQueryProvider接口。

    创建数据源

    那么我们的Product数据在那么找到呢?

    我们先假设数据是放在内存里面,这样实现比较简单。现在我们第一步先编写一个基类:

    public abstract class DSPContext

    {

        public abstract IQueryable GetQueryable(ResourceSet set);

    }

    然后我们设计一个仅能处理Products数据的强类型类,看起来像这样:

    public class ProductsContext: DSPContext

    {

        private List<Product> _products = new List<Product>();

        public override IQueryable GetQueryable(ResourceSet set)

        {

            if (set.Name == "Products") return Products.AsQueryable();

            throw new NotSupportedException(

                string.Format("{0} 未找到", set.Name)

           );

        }

        public List<Product> Products

        {

            get {

                return _products;

            }

        }

    }

    到目前还是蛮简单的,你应该明白其ResourceSet背后的数据源就是一个简单的List

    这里需要注意的是,由于我们的数据放在内存里,所以我们这里使用了LINQ to Objects技术提供的.AsQueryable()方法实现IQueryable的返回值。

    接下来,我们需要修改我们的Sample服务类,他使用ProductsContext作为数据源。

    public class Sample : DSPDataService<ProductsContext>

    {

    我们还需要重载这个类的CreateDataSource方法,以便预先加入一些测试数据进去。

    protected override ProductsContext CreateDataSource()

    {

        ProductsContext context = new ProductsContext();

        context.Products.Add(

            new Product {

                ProdKey = 1,

                Name = "Bovril",

                Cost = 4.35M,

                Price = 6.49M

            });

        context.Products.Add(

           new Product {

                ProdKey = 2,

                Name = "Marmite",

                Cost = 4.97M,

                Price = 7.21M

            });

        return context;

    }

    最后一步,我们需要完成GetQueryProvider方法(需要参见前面教程中Sample类的代码,那个时候我们填写的是Object,而不是下面的ProductsContext)。

    public override IDataServiceQueryProvider GetQueryProvider(

        IDataServiceMetadataProvider metadata)

    {

        return new DSPQueryProvider<ProductsContext>(metadata);

    }

    为强类型数据实现IDataServiceQueryProvider

    现在,我们需要重新编写上个教程章节中编写的DSPQueryProvider<T>类,当时那个类很多功能都没有实现。

    而我们现在需要实现一个对内存中强类型类数据的查询提供者,这里所说的“强类型类”是指:使用ResourceType描述类型信息并且其描述的属性都能够找到真实的CLR属性与之对应。

    代码如下:

    public class DSPQueryProvider<T> : IDataServiceQueryProvider where T : DSPContext

    {

        T _currentDataSource;

        IDataServiceMetadataProvider _metadata;

     

        public DSPQueryProvider(IDataServiceMetadataProvider metadata)

        {

            _metadata = metadata;

        }

        public object CurrentDataSource

        {

            get { return _currentDataSource;}

            set { _currentDataSource = value as T; }

        }

        public IQueryable GetQueryRootForResourceSet(

           ResourceSet resourceSet)

        {

            return _currentDataSource.GetQueryable(resourceSet);

        }

        public ResourceType GetResourceType(object target)

        {

            Type type = target.GetType();

            return _metadata.Types

               .Single(t => t.InstanceType == type);

        }

        public bool IsNullPropagationRequired

        {

            get {return true; }

        }

        public object GetOpenPropertyValue(

            object target,

            string propertyName)

        {

            throw new NotImplementedException();

        }

        public IEnumerable<KeyValuePair<string, object>> GetOpenPropertyValues(object target)

        {

            throw new NotImplementedException();

        }

        public object GetPropertyValue(

            object target,

            ResourceProperty resourceProperty)

        {

            throw new NotImplementedException();

        }

        public object InvokeServiceOperation(

           ServiceOperation serviceOperation,

           object[] parameters)

        {

            throw new NotImplementedException();

        }

    }

    实现说明

    在上面的实现中,CurrentDataSource内部使用_currentDataSource变量记录,其最终运行时指向ProductsContext的实例。

    在下面的GetQueryRootForResourceSet方法中,我们使用了_currentDataSource.GetQueryable()方法返回特定ResourcceSet(资源集)的查询对象(IQueryable)

    我们还实现了GetResourceType(object)方法,他首先获取TargetCLR类型,然后在IDataServiceMetadataProvider.Types中使用InstanceType查找与之匹配的类型。

    最后,IsNullPropagationRequired属性返回了true,因为我们必须让Data Services处理LINQ to Objects无法处理的null

    什么是NullPropagation

    让我们来看看一个LINQ的查询例子:

    var results = from x in queryRoot

                  select x.Customer.Name;

    在这个例子里,如果x.Customernull值,那么程序运行时将抛出NullReferenceException异常。

    可以在上面的IsNullPropagationRequired属性实现中返回true,这样Data Services就会检查查询的数据是否是null从而防止出错。

    注意:诸如LINQ to SQLLINQ to Entity 这样的IQueryables数据库查询实现,是支持null值传播的,无须返回true

    哪些是未实现的

    由于我们的Data Service Provider是针对强类型实体实现的,所以Data Services永远不会调用GetPropertyValue方法,因为默认情况下系统直接从实例的属性上读取。

    译者注:可以查看一下ResourceProperty类包含CanReflectOnInstanceTypeProperty属性,默认情况下此属性返回true,表示直接使用反射获取值(实际上使用了Expression.Property加快了访问速度)。

    在当前实现的模型中,我们没有支持服务操作(ServiceOperation)、开放类型(OpenType)和开放属性(OpenProperty),所以我们都在对应的方法中抛出了NotImplemented异常。

    总结

    最终我们完成了只读方式的数据查询功能,键入:http://localhost/simple.svc/products看起来像这样:

    我们还有很长的路要走,在后面的教程中,我们将逐步增加一些功能支持,包括数据更新、关系、服务操作、流、分页和开放类型,以及展现没有对应的CLR类型的情况。

  • 相关阅读:
    更新 anaconda
    spyder 每次运行前,清除上一次运行的变量
    vscode 无法使用 jupyter notebook
    vscode 关闭当前光标所在变量自动高亮
    vscode 关闭侧边栏中 git source control 的更改数目
    【java】Java组件概览(1)
    【java】字符串处理技巧记录
    【异常处理】Spring项目异常如何做异常处理
    【Springboot】Springboot学习(转)
    【微服务】微服务(转)
  • 原文地址:https://www.cnblogs.com/tansm/p/DSP6.html
Copyright © 2020-2023  润新知