2010-05-11 8 views
3

Je travaille sur un énorme projet ancien avec beaucoup de code fragile, dont certains ont été autour depuis l'ère .NET 1.0, et il a été et sera travaillé par d'autres personnes ... donc je ' J'aimerais changer le moins possible.Puis-je créer une classe personnalisée qui hérite d'un DataRow fortement typé?

J'ai un projet dans ma solution qui contient DataSet.xsd. Ce projet compile à un assembly séparé (Data.dll). Le schéma de la base de données comprend plusieurs tables disposées de manière plus ou moins hiérarchique, mais la seule façon de lier les tables est de passer par des jointures. Je peux obtenir, par exemple. DepartmentRow et EmployeeRow objets du code généré automatiquement. EmployeeRow contient des informations provenant de DepartmentRow correspondant de l'employé via une jointure.

Je crée un nouveau rapport pour voir plusieurs départements et tous leurs employés. Si j'utilise le schéma d'accès aux données existant, tout ce que je peux obtenir est une sortie semblable à une feuille de calcul où chaque employé est représenté sur une ligne, avec des informations de département répétées à plusieurs reprises dans ses colonnes appropriées. .: par exemple

Department1...Employee1... 
Department1...Employee2... 
Department2...Employee3... 

Mais ce que le client souhaite est que chaque département rend comme un titre, une liste des employés sous chacun. E.g .:

- Department1... 
     Employee1... 
     Employee2... 
+ Department2... 

J'essaye de faire ceci en héritant des objets hiérarchiques des objets Row générés automatiquement. .: par exemple

public class Department : DataSet.DepartmentRow { 
    public List<Employee> Employees; 
} 

De cette façon, je pouvais imbriquer les données contenues dans le rapport à l'aide d'une collection du département des objets comme source de données, chacun mettra sa liste d'employés dans un sous-état.

Le problème est que cela me donne une erreur The type Data.DataSet.DepartmentRow has no constructors defined. Et quand j'essaie de créer un constructeur, par exemple Je reçois une erreur 'Data.DataSet.DepartmentRow(System.Data.DataRowBuilder)' is inaccessible due to its protection level. en plus de la première.

Existe-t-il un moyen d'accomplir ce que j'essaie de faire? Ou y a-t-il autre chose que je devrais essayer entièrement?

+1

Je ressens votre douleur ... – SLaks

Répondre

1

J'ai finalement trouvé une solution qui présente les avantages suivants:

  1. Je n'ai pas d'ajouter un ami à l'assemblée de données; Je n'ai qu'à modifier un fichier dans la partie de l'assemblage où je fais normalement des modifications.
  2. Je n'ai pas modifier le code généré automatiquement qui sera remplacé dès qu'il est à nouveau généré

Dans le fichier code-behind pour l'ensemble de données (DataSet.cs, acessed dans VS2008 en élargissant DataSet.xsd), j'ai ajouté une nouvelle définition de classe partielle qui ajoute un constructeur public avec une signature différente, mais qui est fonctionnellement identique au constructeur interne existant:

public partial class DataSet { 
    public partial class DepartmentRow { 
     public DepartmentRow(global::System.Data.DataRowBuilder rb, string discard) : this(rb) { } 
    } 
    public partial class EmployeeRow { 
     public EmployeeRow(global::System.Data.DataRowBuilder rb, string discard) : this(rb) { } 
    } 
} 

Ensuite, je peux utiliser ce constructeur dans ma classe dérivée:

public class Department : DataSet.DepartmentRow { 
    public Department(global::System.Data.DataRowBuilder DataRowBuilder rb) : base(rb, "discard") { } 

    public List<Employee> Employees; 

    public string[] SomeFrequentlyUsedGroupOfFields { 
     get { 
      return new string[] { this.OneField, this.AnotherField }; 
     } 
    } 

    public bool CanUserSeeDepartmentInformation(int UserID) { } 
} 

Et voila!

Malheureusement, après avoir obtenu ce résultat, je compris que ce n'est pas une grande utilité, car le code généré automatiquement dans DataSetTableAdapters.DepartmentTableAdapter retourne encore des objets de type DataSet.DepartmentRow, et je dois downcaster pour obtenir mon objet Department avec les propriétés supplémentaires/méthodes Ce n'est pas permis, et je ne vois pas un moyen facile de contourner ce fait.

Je pourrais simplement déplacer tous mes nouveaux membres vers le code de classe partielle derrière, mais je ne suis pas sûr de savoir quelles spécifications d'architecture pourraient violer. (Il semble y avoir une application arbitraire de la distinction entre la logique de données et la logique métier.)

4

J'ai été capable d'hériter d'une ligne de données dans un test rapide. Notez que ceci est dans le même assembly que la classe de ligne de données. Le constructeur de la classe de lignes de données est marqué comme 'interne'.

using System; 
using System.Data; 

namespace Blah 
{ 
    /// <summary> 
    /// Summary description for Class1. 
    /// </summary> 
    public class Class1 : MyDataSet.MyTableRow 
    { 
     public Class1(DataRowBuilder rb) : base(rb) 
     { 
      // 
      // TODO: Add constructor logic here 
      // 
     } 
    } 
} 
+0

J'ai testé cela jusqu'à la construction du projet. Je ne le ferais toujours pas dans mon propre code, même si je comprends pourquoi tu le veux. – chilltemp

+0

L'avez-vous essayé avec le DataSet dans un autre assemblage? J'ai essayé cela sur mon exemple et j'ai obtenu l'erreur "inaccessible en raison de son niveau de protection". –

+1

Vous ne pouvez pas faire cela dans un assemblage différent sans modifier les accesseurs dans le code d'origine. – chilltemp

Questions connexes