书接上回,如何指定一个list的数据来源呢?比如我们已经存在的数据库。这就是BCS(Business Connectivity Service)要解决的问题。
咱是MOSS的完全新手,概念性的东西不敢讲,就直接说说应用:本篇的主题就是如何把NorthWind数据库中的Product表直接呈现在一个MOSS的list中。
呃。。。不得不说一句的是为什么这一篇的标题是(一)呢?因为现在遇到了技术难题,胜利就在眼前了却总是还差那么一点。。。也就是说(二)啥时候能出来未知。。。看官觉得受骗了的话就请就此打住吧。。。
以下内容是以陈希章老师的《MOSS 2010:Visual Studio 2010开发体验》系列作为基础的,包括笔者一点点自己的探索。
那么正题开始,MOSS中从外部导入External Content Types的途径有三种
直接连接数据库 参考
通过WCF服务 参考
本文将使用的是最后一种方式(估计也会是开发中真正常用的方式),以下将架设看官至少读过了陈老师的两篇参考。
于是我们可以看到自定义BCS Model最基本的步骤如下:
1 实现Entity(比如对应数据库里的一张表)
2 实现对应的Service,实现其中的一些或者全部operation(例如ReadList)
3 通过配置告诉MOSS Entity的类型,它的各个(应该不需要是所有)property的名字,类型等信息,以及其中以哪个为identifier(例如表的主键)
4 deploy
5 在SharePoint Designer(SPD)中使用BDC Model创建list
6 当然就是收获胜利的果实了
于是开始动手,一点一点的说
1 实现Entity
本例准备实现NorthWind数据库中的Product表的BCS连接器,那么Entity自然是Product类。ORM笔者选择了Linq To SQL(最省事,一拖拽就完)
于是VS2010生成的Entity1这个类就没有必要了,删掉。
2 实现EntityService
笔者实现了两个operation,代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Linq; namespace BdcModel { public class ProductService { private static readonly string connectionString = "Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True"; private static NorthWindDataContext dataContext = new NorthWindDataContext(connectionString); public static Product ReadItem(int id) { return dataContext.Products .Where(p => p.ProductID == id) .FirstOrDefault(); } public static IEnumerable<Product> ReadList() { return dataContext.Products; } } }
3 配置Product.bdcm
陈老师的文章里介绍了使用BDC Explorer的配置方法。实际上bdcm是个XML,有VS的智能感知,其实手写起来也不比手写nhibernate的hbm或者Spring.NET更难,笔者选择了手写。
当然如果微软肯把这个过程作的更美好一些当然更好。。。
文件如下
<?xml version="1.0" encoding="utf-8"?> <Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/windows/2007/BusinessDataCatalog" Name="Product"> <LobSystems> <LobSystem Name="Product" Type="DotNetAssembly"> <LobSystemInstances> <LobSystemInstance Name="Product" /> </LobSystemInstances> <Entities> <Entity Name="Product" Namespace="BdcModel" Version="1.0.0.4"> <Properties> <Property Name="Class" Type="System.String">BdcModel.ProductService, BdcModel</Property> </Properties> <Identifiers> <Identifier Name="ProductID" TypeName="System.Int32"/> </Identifiers> <Methods> <Method Name="ReadList"> <Parameters> <Parameter Name="productList" Direction="Return"> <TypeDescriptor Name="ProductList" TypeName="System.Collections.Generic.IEnumerable`1[BdcModel.Product]" IsCollection="true"> <TypeDescriptors> <TypeDescriptor Name="Product" TypeName="BdcModel.Product" IsCollection="false"> </TypeDescriptor> </TypeDescriptors> </TypeDescriptor> </Parameter> </Parameters> <MethodInstances> <MethodInstance Name="ReadList" Type="Finder" ReturnParameterName="productList" ReturnTypeDescriptorPath="ProductList" /> </MethodInstances> </Method> </Methods></Entity> </Entities> </LobSystem> </LobSystems> </Model>
这里笔者偷了懒:其一是只描述了一个Method,其二是没有描述Product类(本来是想看看微软能不能直接把所有property都显示,结果发现不行。。。)
4 deploy
前几次部署的过程比较顺利,后来出现过以下错误
Error occurred in deployment step 'Add Solution': Property 'SiteUrl' contains an invalid URL.
Google之,解决之道是编辑Feature1.Template.xml,添加SiteUrl property,文件编辑后如下
<?xml version="1.0" encoding="utf-8" ?> <Feature xmlns="http://schemas.microsoft.com/sharepoint/"> <Properties> <Property Key="GloballyAvailable" Value="true" /> <Property Key="SiteUrl" Value="http://localhost/sites/lianzTest/"/> </Properties> </Feature>
当然这么做很不爽,难道每新建一个BDC Model都要指定SiteUrl?但是为什么前几次deploy的时候不指定这个属性也没事?这个问题笔者以后有空会继续研究。现在有一点可以怀疑的是笔者改过csproj.user文件,把其中的SharePointSiteUrl中的机器名部分改成了localhost,不知是不是这个原因导致
5 在SPD中创建list
笔者也遭遇了在SPD中点击External Content Types时出现“The Business Data Connectivity Metadata Store is currently unavailable”错误的问题,Google得到的结果基本都是说装WCF HotFix但是笔者使用的环境里这个补丁已经装过了,且重启过了。
最后的解决是卸载了beta版的SPD,安装RTM版,就OK了= =
话说上一篇之后为啥那么久才出这一篇?都是卡在了这里啊~~~~眼泪哗哗的~~~~
总之最终结果是能看到了,如下图
点进去之后
很明显的没有Field,还被提示说少实现了一个operation,偷懒是要不得的啊= =
老老实实的改Product.bdcm,成如下的样子
<?xml version="1.0" encoding="utf-8"?> <Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/windows/2007/BusinessDataCatalog" Name="Product"> <LobSystems> <LobSystem Name="Product" Type="DotNetAssembly"> <LobSystemInstances> <LobSystemInstance Name="Product" /> </LobSystemInstances> <Entities> <Entity Name="Product" Namespace="BdcModel" Version="1.0.0.4"> <Properties> <Property Name="Class" Type="System.String">BdcModel.ProductService, BdcModel</Property> </Properties> <Identifiers> <Identifier Name="ProductID" TypeName="System.Int32"/> </Identifiers> <Methods> <Method Name="ReadList"> <Parameters> <Parameter Name="productList" Direction="Return"> <TypeDescriptor Name="ProductList" TypeName="System.Collections.Generic.IEnumerable`1[BdcModel.Product]" IsCollection="true"> <TypeDescriptors> <TypeDescriptor Name="Product" TypeName="BdcModel.Product" IsCollection="false"> <TypeDescriptors> <TypeDescriptor TypeName="System.Int32" Name="ProductID" IdentifierName="ProductID"/> <TypeDescriptor TypeName="System.String" Name="ProductName"/> </TypeDescriptors> </TypeDescriptor> </TypeDescriptors> </TypeDescriptor> </Parameter> </Parameters> <MethodInstances> <MethodInstance Name="ReadList" Type="Finder" ReturnParameterName="productList" ReturnTypeDescriptorPath="ProductList" /> </MethodInstances> </Method> <Method Name="ReadItem"> <Parameters> <Parameter Name="product" Direction="Return"> <TypeDescriptor Name="Product" TypeName="BdcModel.Product" IsCollection="false"> <TypeDescriptors> <TypeDescriptor TypeName="System.Int32" Name="ProductID" IdentifierName="ProductID"/> <TypeDescriptor TypeName="System.String" Name="ProductName"/> </TypeDescriptors> </TypeDescriptor> </Parameter> <Parameter Name="id" Direction="In"> <TypeDescriptor Name="Id" TypeName="System.Int32" IsCollection="false"/> </Parameter> </Parameters> <MethodInstances> <MethodInstance Name="ReadItem" Type="SpecificFinder" ReturnParameterName="product" ReturnTypeDescriptorPath="Product"/> </MethodInstances> </Method> </Methods></Entity> </Entities> </LobSystem> </LobSystems> </Model>
笔者又偷了懒,只配置了Product类中的两个属性:ProductID和ProductName。之后再deploy,貌似OK了,效果如下
高高兴兴的去创建了自己的Test Product List,准备收获胜利果实了~~~
6 验证创建的list
上来就杯具的报错了= = Access denied by Business Data Connectivity
首先怀疑的是没有数据库访问权限,排查了一通无果,只得继续Google。原来是权限的问题
Central Administration -> Application Management -> Manage Service Applications ->Business Data Connectivity Service -> Product -> Set Permissions
MOSS的安全模型估计也要花相当的时间来学了,这里先不管三七二十一,赋予所有权限
再view list,又出错了。。。
依照提示在SPD里查看,得到如下的错误
soap:ServerException of type 'Microsoft.SharePoint.SoapServer.SoapServerException' was thrown.An error has occurred.
笔者目前就卡在这里了,Google了半天无果,msdn上有几个人问同样的问题,目前也没有正解。
只有继续研究了,MOSS2010的资料还太少啊~~