如何最好地使用OOP来克服两种不同的数据库系统设计

本文关键字:两种 系统设计 数据库 克服 何最好 OOP | 更新日期: 2023-09-27 17:58:05

我需要编写一些中间件代码来在两个第三方学生系统之间移动数据。这两个系统都有自己完全不同的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在架构上将这些结合在一起,以便编写和维护最少的连接代码?如果可以的话,我想使用继承来减少编码和维护?有更好的方法吗?

如何最好地使用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/
  • 错误处理-基本的错误处理是可以的,但我正在将大块数据从一个数据库表移动到另一个。如果数据中出现异常,我需要知道发生异常的表/行/列。为此需要一段时间才能实现解决方案