我需要编写一些中间件代码来在两个第三方学生系统之间移动数据。这两个系统都有自己完全不同的Web服务API。我的计划是在每个Web服务API的顶部构建自定义包装器,然后在两个包装器的顶部构建一个公共程序集,以便在系统之间移动数据,并允许在公共代码库上进行进一步开发。大约有12个其他应用程序直接使用这些系统,维护变得难以管理。我想建立一些他们可以迁移到的东西。
在伪码中
//System one out puts
Class Student_SytemA {
Public StudentID {get;set;} //PKID System A
Public FName {get;set;}
Public LName {get;set;}
Public DOB {get;set;}
}
//System two out puts
Class Student_SystemB{
Public ContactID {get;set;} //PK SystemB
Public FirstName {get;set;}
Public LastName {get;set;}
Public DateOfBirth {get;set;}
Public StudentID_REF {get;set;} //Reference to System A
}
这类事情在两个系统中都很普遍,因为它们在不同的字段名或数据结构下持有完全相同的信息。
我的想法是有这样的
Class Student_Comman{
Public ContactID {get;set;}
Public FirstName {get;set;}
Public LastName {get;set;}
Public DateOfBirth {get;set;}
Public StudentID_REF {get;set;}
Public WireUpSystemA(Student_SystemA student){
StudentID_REF = student .StudentID;
FirstName = student .FName ;
LastName = student .LName ;
DateOfBirth = student .DOB ;
}
Public WireUpSystemB(Student_SystemB student){
StudentID_REF = student . StudentID_REF ;
FirstName = student . FirstName ;
LastName = student . LastName;
DateOfBirth = student . DateOfBirth;
}
}
我该如何使用OOP在架构上将这些结合在一起,以便编写和维护最少的连接代码?如果可以的话,我想使用继承来减少编码和维护?有更好的方法吗?
对于像您这样的情况,我更喜欢反射/通用方法。
用一个属性标记A和B的属性,该属性告诉目标类型中必须映射到哪个属性,并只创建一个通用转换器:
//Custom attribute class
sealed class RedirectedPropertyAttribute : Attribute
{
readonly string targetProperty;
public RedirectedPropertyAttribute(string TargetProperty)
{
this.targetProperty = TargetProperty;
}
public string TargetProperty
{
get { return targetProperty; }
}
}
//Type converter
public class TypeConverter
{
public static T Convert<T, S>(S Source) where T : class, new() where S : class, new()
{
//If no instance is passed just return null
if (Source == null)
return null;
//Get types of items
Type typeOfTarget = typeof(T);
Type typeOfSource = typeof(S);
//Get properties of items
var sourceProperties = typeOfSource.GetProperties();
var targetProperties = typeOfTarget.GetProperties();
//Create a new instance of T
var instance = Activator.CreateInstance<T>();
foreach (var prop in sourceProperties)
{
//Get or attributes
var attribs = prop.GetCustomAttributes(typeof(RedirectedPropertyAttribute), false); //If you want to inherit the attributes change to yes
//If it's not marked or marked more than once, continue (really a bad error ;))
if (attribs == null || attribs.Length != 1)
continue;
//Cast the attribute
RedirectedPropertyAttribute attrib = attribs[0] as RedirectedPropertyAttribute;
//No property set? ignore this property
if (string.IsNullOrWhiteSpace(attrib.TargetProperty))
continue;
//Find the target property in target type
var tProp = targetProperties.Where(t => t.Name == attrib.TargetProperty).FirstOrDefault();
//Not found? ignore this property
if (tProp == null)
continue;
try
{
//Why this try-catch?
//Because if types don't match an exception can be thrown
//but it's easier than comparing types (because if an int is mapped to a long we want it to be set)
//WARNING!!, assuming non-indexed properties!
tProp.SetValue(instance, prop.GetValue(Source, null), null);
}
catch { }
}
//Return new class
return instance;
}
}
//Class from source A
public class A
{
[RedirectedProperty("Id")]
public int IdOfA { get; set; }
[RedirectedProperty("Name")]
public string StringOfA { get; set; }
}
//Class from source B
public class B
{
[RedirectedProperty("Id")]
public int IdOfB { get; set; }
[RedirectedProperty("Name")]
public string StringOfB { get; set; }
}
//Hub class for A or B
public class ABHub
{
public int Id { get; set; }
public string Name { get; set; }
}
//And to use:
ABHub ACasted = TypeConverter.Convert<ABHub, A>(new A{ IdOfA = 33, StringOfA = "MyNameIsA" });
ABHub BCasted = TypeConverter.Convert<ABHub, B>(new B{ IdOfB = 33, StringOfB = "MyNameIsB" });
在两个第三方系统之间移动数据可能很难维护,尤其是当它们可能更改其公开的属性/方法时。
您的项目范围只是在两个系统之间来回移动数据吗?如果是,请查看SSIS包。
以下是SSIS:的一些好处
- SSIS包的核心用例是将数据从一个位置移动到另一个位置。这也被称为ETL(提取转换负载)
- 列及其映射到的内容的可视化显示
- 可以在SSIS中创建用C编写的自定义模块#
- SSIS包的学习曲线非常低。它们很容易创建
以下是SSIS的一些缺点:
- 没有对RESTful服务的本机支持。然而,这篇文章似乎有一个很好的解决方案:https://markarlenplace.wordpress.com/2010/12/30/consuming-restful-web-services-in-an-ssis-script-transformation/
- 错误处理-基本的错误处理是可以的,但我正在将大块数据从一个数据库表移动到另一个。如果数据中出现异常,我需要知道发生异常的表/行/列。为此需要一段时间才能实现解决方案