【问题标题】:From child class, call base class method while using child fields从子类,在使用子字段时调用基类方法
【发布时间】:2020-01-09 22:09:55
【问题描述】:

我用一个方法创建了一个小型 ETL 程序,它只接受源数据库的连接字符串和目标数据库的连接字符串。

基本上有5个步骤:

第 1 步。从源中选择数据。
步骤 2. 在目标上创建一个临时表。
步骤 3. 将数据从源加载到目标上的临时。
步骤 4. 将临时表中的数据合并到实际目标表中。
步骤 5. 删除临时表

这对于需要进行的单个转换非常有效,但我有大约 20 个不同的 ETL“工作”需要进行。

因此,与其逐字复制和粘贴相同的方法 19 次不同,我想定义一个基类来定义这个单一方法一次,然后从每个子类调用这个单一方法,用它自己的选择,创建, 合并和删除语句。

这可能吗?

基类:

public class ETLBase
{

    private static string Select;
    private static string CreateTemp;
    private static string Merge;
    private static string CleanUp;
    private static string DestinationTable;


    public static void ExecuteJob(string sourceConnectionString, string destinationConnectionString)
    {
        using (OracleConnection sourceConnection = new OracleConnection(sourceConnectionString))
        {
            sourceConnection.Open();

            OracleCommand selectCommand = new OracleCommand(Select, sourceConnection);
            OracleDataReader reader = selectCommand.ExecuteReader();

            using (SqlConnection destinationConnection = new SqlConnection(destinationConnectionString))
            {
                destinationConnection.Open();

                SqlCommand createTempCommand = new SqlCommand(CreateTemp, destinationConnection);
                createTempCommand.ExecuteNonQuery();

                SqlCommand mergeCommand = new SqlCommand(Merge, destinationConnection);
                SqlCommand dropCommand = new SqlCommand(CleanUp, destinationConnection);

                using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection))
                {
                    bulkCopy.DestinationTableName = DestinationTable;

                    try
                    {
                        bulkCopy.WriteToServer(reader);
                        mergeCommand.ExecuteNonQuery();
                        dropCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        reader.Close();
                    }
                }
            }
        }
    }
}

儿童班:

public class ChildETL: ETLBase
{
    private static string Select = @"Select THIS DataStatement";
    private static string CreateTemp = @"CREATE TABLE Statement";
    private static string Merge = @"Merge Table statement";
    private static string CleanUp = "DROP TABLE Statement";
    private static string DestinationTable = "##TempTable";
}

然后像这样执行它,但是每个子类使用自己定义的字段,所以它使用自己的 SQL 语句。

public class Program
{
    public static void Main(string[] args)
    {
        IConfiguration config = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", true, true)
            .Build();

        string schoolDBConnection = config["SchoolConnection"];
        string courseDBConnection = config["CourseConnection"];
        string teacherDBConnection = config["Connection"];

        ChildETLA.ExecuteJob(schoolDBConnection, courseDBConnection);
        ChildETLB.ExecuteJob(teacherDBConnection, courseDBConnection);

        //...and so on for each child ETL class

    }

}

【问题讨论】:

  • 类继承仅适用于实例属性/方法。也许您可以更新基类的方法以接收 Select、CreateTemp 等作为参数,将该方法标记为受保护,并在您调用包含参数的基类方法的每个子类上创建一个新的 ExecuteJob 方法。我希望这会有所帮助。
  • 在这种情况下没有真正需要使用继承。只需将命令字符串添加为方法参数,然后从每个作业中调用 ExecuteJob() 方法。

标签: c# sql oop inheritance .net-core


【解决方案1】:

首先,您需要多态地运行“ExecuteJob()”,这意味着“ExecuteJob”的行为将根据源连接字符串和目标连接字符串而有所不同。您无法实现静态函数或属性的多态性。首先,您需要通过取出“静态”关键字将其重构为实例方法。此外,基类的行为由子类决定,因此没有人应该能够创建基类的对象以使其成为抽象类。查看您的代码,您有两种行为,一种是针对学校的,另一种是针对老师的。所以你必须创建两个不同的继承抽象基类的子类。对象创建的责任是用源和目标连接字符串组合对象,因此将其传递给构造函数并在创建对象本身时设置它。请找到重构后的代码,

public abstract class ETLBase
{
    private readonly string sourceConnectionString;
    private readonly string destinationConnectionString;

    protected virtual string Select { get; set; } = @"Select THIS DataStatement";
    protected virtual string CreateTemp { get; set; } = @"CREATE TABLE Statement";
    protected virtual string Merge { get; set; } = @"Merge Table statement";
    protected virtual string CleanUp { get; set; } = "DROP TABLE Statement";
    protected virtual string DestinationTable { get; set; } = "##TempTable";


    protected ETLBase(string sourceConnectionString, string destinationConnectionString)
    {
        this.sourceConnectionString = sourceConnectionString;
        this.destinationConnectionString = destinationConnectionString;
    }

    public void ExecuteJob()
    {
        using (OracleConnection sourceConnection = new OracleConnection(sourceConnectionString))
        {
            sourceConnection.Open();

            OracleCommand selectCommand = new OracleCommand(Select, sourceConnection);
            OracleDataReader reader = selectCommand.ExecuteReader();

            using (SqlConnection destinationConnection = new SqlConnection(destinationConnectionString))
            {
                destinationConnection.Open();

                SqlCommand createTempCommand = new SqlCommand(CreateTemp, destinationConnection);
                createTempCommand.ExecuteNonQuery();

                SqlCommand mergeCommand = new SqlCommand(Merge, destinationConnection);
                SqlCommand dropCommand = new SqlCommand(CleanUp, destinationConnection);

                using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection))
                {
                    bulkCopy.DestinationTableName = DestinationTable;

                    try
                    {
                        bulkCopy.WriteToServer(reader);
                        mergeCommand.ExecuteNonQuery();
                        dropCommand.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        reader.Close();
                    }
                }
            }
        }
    }

还有子类,

public class ChildETLSchool : ETLBase
    {
        public ChildETLSchool(string sourceConnectionString, string destinationConnectionString) 
            : base(sourceConnectionString, destinationConnectionString)
        {
            //Change values of below lines only if you want to override the values

            //Select = @"Select THIS DataStatement";
            //CreateTemp = @"CREATE TABLE Statement";
            //Merge = @"Merge Table statement";
            //CleanUp = "DROP TABLE Statement";
            //DestinationTable = "##TempTable";
        }

    }

    public class ChildETLTeacher : ETLBase
    {
        public ChildETLTeacher(string sourceConnectionString, string destinationConnectionString) 
            : base(sourceConnectionString, destinationConnectionString)
        {
            //Change values of below lines only if you want to override the values

            //Select = @"Select THIS DataStatement";
            //CreateTemp = @"CREATE TABLE Statement";
            //Merge = @"Merge Table statement";
            //CleanUp = "DROP TABLE Statement";
            //DestinationTable = "##TempTable";
        }

    }

以及main函数中的对象创建,

static void Main(string[] args)
    {
        IConfiguration config = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json", true, true)
        .Build();

        string schoolDBConnection = config["SchoolConnection"];
        string courseDBConnection = config["CourseConnection"];
        string teacherDBConnection = config["Connection"];

        var childETLSchool = new ChildETLSchool(schoolDBConnection, courseDBConnection);
        var childETLTeacher = new ChildETLTeacher(teacherDBConnection, courseDBConnection);

        childETLSchool.ExecuteJob();
        childETLTeacher.ExecuteJob();
    }

【讨论】:

    猜你喜欢
    • 2016-10-05
    • 1970-01-01
    • 2011-01-05
    • 2011-01-22
    • 2023-03-30
    • 2012-06-28
    • 2018-10-15
    • 1970-01-01
    • 2017-12-13
    相关资源
    最近更新 更多