In general, I want to make a class that will import the DataTable into Access or MS SQL.

The class will have 1 method: Append, to which the DataTable will be fed into the input, and the method in turn will load the DataTable to the desired destination.

Of course, the Access internal logic of the Append can be very different, for example:

  1. In Access, you need to ensure that the file is not higher than 2GB, otherwise the database will break
  2. In MS SQL, you can use BulkCopy, and in Access you will need some kind of samopal.

Accordingly, the designers can vary greatly in parameters, for example:

  1. Connection strings will differ between the two types.
  2. In MS SQL, you can use or not use a transaction
  3. In Access, you can restore or not restore the database after each Append.

What is the best way to arrange all this?

UPD:

I have some suggestions on how this can be done, but I don’t know how true that is.

Make an interface:

public interface IApend { void Append(DataTable dt); } 

Implement it in 2 classrooms, each of which will contain its own import logic:

  public class ImporterToSQL: IApend { //КакиС-Ρ‚ΠΎ поля public void Append(DataTable dt) { //Какая-Ρ‚ΠΎ Π»ΠΎΠ³ΠΈΠΊΠ° } } public class ImporterAccess : IApend { //КакиС-Ρ‚ΠΎ поля public void Append(DataTable dt) { //Какая-Ρ‚ΠΎ Π»ΠΎΠ³ΠΈΠΊΠ° } } 

And create such a class:

  public class Importer { IApend Concrete; public Importer(IApend concrete) { Concrete = concrete; } static Importer ImporterToSQL(object v,object v2,object v3) { return new Importer(new ImporterToSQL(object v, object v2, object v3)); } static Importer ImporterToSQL(object v, object v2) { return new Importer(new ImporterToSQL(object v, object v2)); } static Importer ImporterToAccess(object v, object v2, object v3) { return new Importer(new ImporterAccess(object v, object v2, object v3))); } static Importer ImporterToAccess(object v, object v2) { return new Importer(new ImporterAccess(object v, object v2)); } public void Append(DataTable dt) { Concrete.Append(dt); } } 

How much is this true and how well will this approach work in terms of adding new functionality (for example, I was impatient to add import from SQL to Access)? Is it, like, called a class factory?

    1 answer 1

    You are on the right track. Common interface for conversion is right. Only I would call it a little more specific, although some IImporter would be.

    As for creating specific instances and your class Importer . To create a really need a factory. However, you have it turned out not in its pure form. It makes no sense to wrap an instance in your Importer - you already have an interface. Just create the necessary instances and return them. And the client will already call methods directly:

     public static class ImporterFactory { static IImporter CreateSQLImporter(object v, object v2, object v3) { return new ImporterToSQL(v, v2, v3); } static IImporter CreateAccessImporter(object v, object v2, object v3) { return new ImporterAccess(v, v2, v3); } // ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅ } 

    As parameters for constructors, you probably have specific data for each implementation: for example, a connection string for SQL and the path to the mdb file for Access. Ideally, the client should not know anything about the implementation details at all, and the factory should contain one method per type. All implementation details are hidden in the factory, which slips the necessary parameters directly from the configuration (for example, from app.config). At the same time, the client will not know anything about the implementation at all:

     public static class ImporterFactory { static IImporter CreateImporter(object v) { var generalConfig = GetGeneralConfig(); if (generalConfig.Type == "sql") { var config = GetSqlImporterConfig(); return new ImporterToSQL(config.ConnectionString, v); } else if (generalConfig.Type == "access") { var config = GetAccessImporterConfig(); return new ImporterToAccess(config.ConnectionString, v); } } } 

    This approach will work very well if you need to import to a new place. You just write another implementation of IImporter , make changes to the ImporterFactory and that's it. All clients that use IImporter will not have to change. In the case of individual methods, you will have to change the calling code that controls which method to call.


    As for importing from SQL into Access, this problem cannot be solved by the method described above. Above, we considered only the task β€œto write data as a data presented in a universal form (DataTable) to a specific place”. The import task from SQL to Access can be reformulated as "how to extract data from one place and write it to another place." Such a task is useful to break into two steps and enter an intermediate stage. Which one That's right, getting data in a universal form. Thus, there will be two steps:

    1. Import from source with conversion to universal view
    2. Export to another location

    Accordingly, the two main contracts will look something like this:

     interface IImporter { DataTable Import(); } interface IExporter { void Export(DataTable data); } 

    You already have the implementation of the second step, the truth is now called import. In the presence of two steps, it would be more logical to call them with t. how data moves relative to your application . You import (upload) data from one source and export (upload) it to another location.

    The implementation of the first step will be similar - various interface implementations, factory.

    To complete the conversion process, you will need some general entity that will combine the steps. It can accept as dependencies both the factory and the importer / exporter instances:

     public class DataConverter // ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°ΠΉΡ‚Π΅ имя ΠΏΠΎΡƒΠ΄Π°Ρ‡Π½Π΅Π΅, поТалуйста :) { private readonly IImporter _importer; private readonly IExporter _exporter; public DataConverter(IImporter importer, IExporter exporter) { _importer = importer; _exporter = exporter; } public void Convert() { var data = _importer.Import(); _exporter.Export(data); } }