本篇文章中我主要讲的是.NET如何通过RFC从SAP中读取数据。为了功能的可复用性,我将调用RFC的代码从业务层中分离出来单独建立在一个namespace中。
当然除了需要我们自己编写代码以外,还需要引用SAP提供的程序集文件(sapnco.dll、sapnco_utils.dll),在代码文件需要引用相应的命名空间(using SAP.Middleware.Connector;)。
我在这个namespace中建立了三个类来实现这个功能,一个配置类(RfcDestinationConfig)、一个参数类(RfcParam)、一个主体功能类(RfcManager)。
- RfcDestinationConfig
我们需要一个类来实现SAP的连接配置工作,就如同为数据连接层建立一个数据库配置类一样重要。
1 public class RfcDestinationConfig : IDestinationConfiguration 2 { 3 #region 事件 4 /// <summary> 5 /// 配置变更事件 6 /// </summary> 7 public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged; 8 /// <summary> 9 /// 默认接收器名称 10 /// </summary> 11 public static readonly string DefaultDesName = "destination"; 12 #endregion 13 14 #region 方法 15 /// <summary> 16 /// 配置变更事件触发时,暂时无用 17 /// </summary> 18 /// <param name="destinationName"></param> 19 /// <param name="args"></param> 20 public void OnConfigurationChanged(string destinationName, RfcConfigurationEventArgs args) 21 { 22 if (ConfigurationChanged != null) 23 { 24 ConfigurationChanged(destinationName, args); 25 } 26 } 27 28 /// <summary> 29 /// 获取SAP配置参数 30 /// </summary> 31 /// <param name="destinationName"></param> 32 /// <returns></returns> 33 public RfcConfigParameters GetParameters(string destinationName) 34 { 35 if (destinationName == DefaultDesName) 36 { 37 RfcConfigParameters parms = new RfcConfigParameters(); 38 parms.Add(RfcConfigParameters.AppServerHost,ConfigManager.GetAppSettings("SAPApplicationServer").Trim()); //SAP主机IP 39 parms.Add(RfcConfigParameters.SystemNumber, ConfigManager.GetAppSettings("SAPSystemNumber").Trim()); //SAP实例 40 parms.Add(RfcConfigParameters.User, ConfigManager.GetAppSettings("SAPUser").Trim()); //用户名 41 parms.Add(RfcConfigParameters.Password,ConfigManager.GetAppSettings("SAPPwd").Trim()); //密码 42 parms.Add(RfcConfigParameters.Client, ConfigManager.GetAppSettings("SAPClient").Trim()); // Client 43 parms.Add(RfcConfigParameters.Language,ConfigManager.GetAppSettings("SAPLanguage").Trim()); //登陆语言 44 return parms; 45 } 46 else 47 { 48 return null; 49 } 50 } 51 52 /// <summary> 53 /// 变更事件方法,暂时无用 54 /// </summary> 55 /// <returns>true</returns> 56 public bool ChangeEventsSupported() 57 { 58 return true; 59 } 60 #endregion 61 }
- RfcParam
想要从SAP中读取数据,就必须将查询条件作为参数传递给RFC。另外为了返回的结果具有通用性,我使用DataTable作为返回结果的类型,然后考虑到不同条件下列是不同的,我又将列也参数化,最终我将输入参数和输出参数都封装在一个参数类之中。
1 public class RfcParam 2 { 3 /// <summary> 4 /// 初始化 5 /// </summary> 6 public RfcParam() 7 { 8 CoulmnNames = new List<string>(); 9 Param = new Dictionary<string, object>(); 10 } 11 /// <summary> 12 /// RFC方法名称 13 /// </summary> 14 public string RfcName { get; set; } 15 /// <summary> 16 /// RFC表名 17 /// </summary> 18 public string TableName { get; set; } 19 /// <summary> 20 /// 数据表各列的列名 21 /// </summary> 22 public List<string> CoulmnNames { get; set; } 23 /// <summary> 24 /// RFC执行参数 25 /// </summary> 26 public Dictionary<string, object> Param { get; set; } 27 }
- RfcManager
该主角登场了,读取数据的功能正是业务层真正想要的东西。
方法ExecRfc首先将输出参数转换成一个真正可用的新的DataTable,然后将输入参数传递给SAP执行相关的RFC功能并返回IRfcTable(SAP定义的一种接口),最后再将IRfcTable转换成我们自定义的DataTable。
1 public class RfcManager 2 { 3 #region 属性字段 4 /// <summary> 5 /// 接收器 6 /// </summary> 7 public RfcDestination Prd { get; set; } 8 /// <summary> 9 /// 数据仓库 10 /// </summary> 11 public RfcRepository Repo { get; set; } 12 #endregion 13 14 #region 构造函数 15 /// <summary> 16 /// 初始化 17 /// </summary> 18 public RfcManager() 19 { 20 //初始化RFC接收器 21 //配置接收器 22 IDestinationConfiguration IDC = new RfcDestinationConfig(); 23 //注册 24 RfcDestinationManager.RegisterDestinationConfiguration(IDC); 25 //获取RFC接收器 26 this.Prd = RfcDestinationManager.GetDestination(RfcDestinationConfig.DefaultDesName); 27 this.Repo = this.Prd.Repository; 28 //注销 29 RfcDestinationManager.UnregisterDestinationConfiguration(IDC); 30 } 31 #endregion 32 33 #region 方法 34 /// <summary> 35 /// 执行RFC获取数据表 36 /// </summary> 37 /// <param name="rfcname">rfc方法名称</param> 38 /// <param name="tablename">rfc表名</param> 39 /// <param name="columnnames">数据表列名列表</param> 40 /// <param name="param">rfc执行参数</param> 41 /// <returns>数据表</returns> 42 public DataTable ExecRfc(string rfcname, string tablename, List<string> columnnames, Dictionary<string, object> param) 43 { 44 DataTable dt = new DataTable(); 45 46 if (columnnames != null && columnnames.Count > 0) 47 { 48 //配置datatable 49 dt.Columns.Clear(); 50 foreach (string cname in columnnames) 51 { 52 dt.Columns.Add(cname, typeof(string)); 53 } 54 dt.AcceptChanges(); 55 56 //从SAP那获取数据表 57 if (!string.IsNullOrEmpty(rfcname) && param != null && param.Count > 0) 58 { 59 IRfcFunction rfc = this.Repo.CreateFunction(rfcname); 60 foreach (KeyValuePair<string, object> kv in param) 61 { 62 rfc.SetValue(kv.Key, kv.Value); 63 } 64 rfc.Invoke(this.Prd); 65 IRfcTable iTable = rfc.GetTable(tablename); 66 if (iTable.Count > 0) 67 { 68 for (int i = 0; i < iTable.RowCount; i++) 69 { 70 iTable.CurrentIndex = i; 71 DataRow oNewRow = dt.NewRow(); 72 foreach (string cname in columnnames) 73 { 74 oNewRow[cname] = iTable.GetString(cname).ToString(); 75 } 76 dt.Rows.Add(oNewRow); 77 } 78 } 79 } 80 } 81 82 return dt; 83 } 84 #endregion 85 }