Modèle de conception pour l'importation de données de divers types de source et vers différents types de destination

14

Je dois concevoir et construire un script d'importation (en C #) qui peut gérer les éléments suivants:

  • lire les données de différentes sources (XML, XSLX, CSV)
  • Vérifiez les données
  • écrire les données dans différents types d'objets (client, adresse)

Les données proviendront d'un certain nombre de sources mais une source aura toujours un format d'importation (csv, xml, xslx). Les formats d'importation peuvent varier d'une source à l'autre. De nouveaux formats d'importation pourraient être ajoutés à l'avenir. Les types d'objets de destination sont toujours les mêmes (client, adresses et quelques autres).

J'ai pensé à utiliser des génériques et j'ai lu quelque chose sur le modèle d'usine, mais je suis un assez grand noob dans ce domaine, donc tout conseil est plus que bienvenu.

Quel est un modèle de conception approprié pour résoudre ce problème?

jao
la source
Rester simple.
NoChance

Réponses:

11

Vous allez trop loin avec des concepts fantaisistes c'était trop tôt. Génériques - lorsque vous voyez un cas, utilisez-les, mais sinon, ne vous inquiétez pas. Modèle d'usine - beaucoup trop de flexibilité (et confusion supplémentaire) pour le moment.

Rester simple. Utilisez des pratiques fondamentales.

  1. Essayez d'imaginer les choses courantes entre faire une lecture pour XML, une lecture pour CSV. Des choses comme, prochain enregistrement, prochaine ligne. Étant donné que de nouveaux formats peuvent être ajoutés, essayez d'imaginer la similitude que le format à déterminer aurait avec les formats connus. Utilisez cette similitude et définissez une «interface» ou un contrat auquel tous les formats doivent adhérer. Bien qu'ils adhèrent au terrain d'entente, ils peuvent tous avoir leurs règles internes spécifiques.

  2. Pour valider les données, essayez de fournir un moyen de connecter facilement des blocs de code de validation nouveaux ou différents. Encore une fois, essayez de définir une interface où chaque validateur, responsable d'un type particulier de construction de données, adhère à un contrat.

  3. Pour créer les constructions de données, vous serez probablement contraint par celui qui conçoit les objets de sortie suggérés plus que tout. Essayez de comprendre quelle est la prochaine étape pour les objets de données, et y a-t-il des optimisations que vous pouvez faire en connaissant l'utilisation finale. Par exemple, si vous savez que les objets vont être utilisés dans une application interactive, vous pouvez aider le développeur de cette application en fournissant des «sommations» ou des dénombrements des objets ou d'autres types d'informations dérivées.

Je dirais que la plupart d'entre eux sont des modèles de modèle ou des modèles de stratégie. L'ensemble du projet serait un modèle d'adaptateur.

Andyz Smith
la source
+1, surtout pour le premier paragraphe (et c'est bien de voir que vous êtes arrivé à la même conclusion que moi dans le dernier paragraphe).
Doc Brown
Gardez également à l'esprit l'architecture de l'ensemble du projet, pour adapter un format à un autre. Pouvez-vous imaginer une situation où quelqu'un pourrait utiliser une seule partie de cela dans un autre projet? EG Peut-être qu'un nouveau validateur de données arrive sur le marché, et il ne fonctionne qu'avec SQL Server. Alors maintenant, vous voulez juste lire le XML personnalisé et le mettre dans le serveur SQL, en ignorant le reste des étapes.
Andyz Smith
Pour faciliter cela, non seulement les pièces doivent avoir leurs contrats internes auxquels elles adhèrent, mais il devrait y avoir un ensemble de contrats qui définissent l'interaction entre les pièces .
Andyz Smith
@AndyzSmith - J'ai le même problème dans mon code. J'ai tout compris de votre code, à l'exception du modèle d'adaptateur. Lorsque vous avez dit que l'ensemble du projet est un exemple de modèle d'adaptateur, pouvez-vous l'illustrer?
gansub
9

La chose évidente est d'appliquer le modèle de stratégie . Avoir une classe de base générique ReadStrategyet pour chaque format d'entrée une sous-classe comme XmlReadStrategy, CSVReadStrategyetc. Cela vous permettra de modifier le traitement d'importation indépendamment du traitement de vérification et du traitement de sortie.

Selon les détails, il peut également être possible de conserver la plupart des parties du générique d'importation et d'échanger uniquement des parties du traitement d'entrée (par exemple, la lecture d'un enregistrement). Cela peut vous conduire au modèle de méthode de modèle .

Doc Brown
la source
Cela signifie-t-il que lorsque j'utilise le modèle de stratégie, je dois créer des méthodes distinctes pour convertir les objets (client, adresse) de la source vers la destination. Ce que je voudrais faire, c'est lire, convertir et valider chaque objet et le mettre dans une liste pour que la liste puisse ensuite être enregistrée dans la base de données.
jao
@jao: eh bien, si vous relisez ma réponse, vous voyez que ma suggestion était de créer "ReadStrategy", pas un "ConvertStrategy". Il vous suffit donc d'écrire différentes méthodes de lecture des objets (ou toute autre partie supplémentaire de votre processus est individuelle pour le format de fichier spécifique).
Doc Brown
7

Un modèle approprié pour un utilitaire d'importation que vous devrez peut-être étendre à l'avenir serait d'utiliser MEF - vous pouvez réduire l'utilisation de la mémoire en chargeant le convertisseur dont vous avez besoin à la volée à partir d'une liste paresseuse, créer des importations MEF décorées d'attributs qui aident à sélectionner le bon convertisseur pour l'importation que vous essayez d'effectuer et fournit un moyen facile de séparer les différentes classes d'importation.

Chaque partie MEF peut être construite pour satisfaire une interface d'importation avec certaines méthodes standard qui convertissent une ligne du fichier d'importation en vos données de sortie ou remplacent une classe de base avec la fonctionnalité de base.

MEF est un cadre pour créer une architecture de plug-in - sa façon dont Outlook et Visual Studio sont construits, toutes ces belles extensions dans VS sont des parties MEF.

Pour créer une application MEF (Managed Extensability Framework), commencez par inclure une référence à System.ComponentModel.Composition

Définir des interfaces pour spécifier ce que fera le convertisseur

public interface IImportConverter
{
    int UserId { set; }        
    bool Validate(byte[] fileData, string fileName, ImportType importType);
    ImportResult ImportData(byte[] fileData, string fileName, ImportType importType);
}

Cela peut être utilisé pour tous les types de fichiers que vous souhaitez importer.

Ajouter des attributs à une nouvelle classe qui définissent ce que la classe "exportera"

[Export(typeof(IImportConverter))]
[MyImport(ImportType.Address, ImportFileType.CSV, "4eca4a5f-74e0")]
public class ImportCSVFormat1 : ImportCSV, IImportConverter
{
 ...interface methods...
}

Cela définirait une classe qui importera des fichiers CSV (d'un format particulier: Format1) et possède des attributs personnalisés qui définissent les métadonnées d'attribut d'exportation MEF. Vous répéteriez cela pour chaque format ou type de fichier que vous souhaitez importer. Vous pouvez définir des attributs personnalisés avec une classe comme:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class ImportAttribute : ExportAttribute
{
    public ImportAttribute(ImportType importType, ImportFileType fileType, string customerUID)
        : base(typeof(IImportConverter))
    {
        ImportType = importType;
        FileType = fileType;
        CustomerUID = customerUID;
    }

    public ImportType ImportType { get; set; }
    public ImportFileType FileType { get; set; }
    public string CustomerUID { get; set; }
}

Pour utiliser réellement les convertisseurs MEF, vous devez importer les pièces MEF que vous créez lors de l'exécution de votre code de conversion:

[ImportMany(AllowRecomposition = true)]
protected internal Lazy<IImportConverter, IImportMetadata>[] converters { get; set; }
AggregateCatalog catalog = new AggregateCatalog();

catalog recueille les pièces d'un dossier, par défaut est l'emplacement de l'application.

converters est une liste paresseuse des pièces MEF importées

Ensuite, lorsque vous savez quel type de fichier vous souhaitez convertir ( importFileTypeet importType) obtenez un convertisseur à partir de la liste des pièces importées dansconverters

var tmpConverter = (from x in converters
                    where x.Metadata.FileType == importFileType
                    && x.Metadata.ImportType == importType 
                    && (x.Metadata.CustomerUID == import.ImportDataCustomer.CustomerUID)
                    select x).OrderByDescending(x => x.Metadata.CustomerUID).FirstOrDefault();

if (tmpConverter != null)
{
     var converter = (IImportConverter)tmpConverter.Value;
     result = converter.ImportData(import.ImportDataFile, import.ImportDataFileName, importType);
....
}

L'appel à converter.ImportData utilisera le code dans la classe importée.

Cela peut sembler beaucoup de code et cela peut prendre un certain temps pour comprendre ce qui se passe, mais c'est extrêmement flexible quand il s'agit d'ajouter de nouveaux types de convertisseurs et peut même vous permettre d'en ajouter de nouveaux pendant l'exécution.

Mat
la source
Je n'ai jamais entendu parler de MEF auparavant. Qu'Est-ce que c'est?
jao
2
@jao consultez le lien pour une explication complète. Ajout de quelques exemples de trucs MEF à ma réponse.
Matt
1
C'est un excellent moyen de démarrer au MEF. +1
paqogomez
MEF est une technologie, pas un modèle de conception. Non -1de ma part, car l'idée sous-jacente a toujours un sens et repose sur un modèle de stratégie régi par l' IImportConverterinterface.
GETah
0

Quel est un modèle de conception approprié pour résoudre ce problème?

Les idiomes C # impliquent d'utiliser le cadre de sérialisation intégré pour ce faire. Vous annotez les objets avec des métadonnées, puis instanciez différents sérialiseurs qui utilisent ces annotations pour extraire les données à mettre sous la bonne forme, ou vice versa.

Les formes Xml, JSON et binaires sont les plus courantes, mais je ne serais pas surpris si d'autres existent déjà sous une belle forme packagée à consommer.

Telastyn
la source
Eh bien, cela fonctionne bien si vous êtes libre d'utiliser votre propre format de fichier, mais je suppose que cette approche échouera pour des formats complexes et prédéfinis comme XSLX, ce qui signifie des fichiers MS Excel au format XML compressé.
Doc Brown
Je peux mapper une ligne d'un fichier Excel sur un objet, mais je devrais copier et adapter cette méthode aux lecteurs XML et CSV. Et je voudrais garder le code aussi propre que possible ...
jao
@docBrown - comment? Conceptuellement, transformer un objet en une série de cellules dans Excel n'est pas vraiment différent de le transformer en un document xml.
Telastyn
@Telastyn: vous dites que vous pouvez utiliser le framework de sérialisation intégré du framework .NET pour lire le format XLSX? Si cela était vrai, des bibliothèques comme le SDK Open XML ou NPOI étaient obsolètes.
Doc Brown
@docbrown: mes excuses, vous avez raison - j'oublie toujours qu'il n'y a pas de classe de base sérialiseur commune car c'est l'une des premières choses qui se fait dans n'importe quelle base de code dans laquelle je travaille.
Telastyn