2009-09-25 4 views
3

Supposons que j'ai une table dans ma base de données qui se compose des colonnes suivantes, dont 3 identifient de manière unique la ligne:Quelle est la conception la plus appropriée pour un objet dont la clé de base de données est composée de plusieurs colonnes?

CREATE TABLE [dbo].[Lines] 
(
    [Attr1] [nvarchar](10) NOT NULL, 
    [Attr2] [nvarchar](10) NOT NULL, 
    [Attr3] [nvarchar](10) NOT NULL, 
    PRIMARY KEY (Attr1, Attr2, Attr3) 
) 

Maintenant, j'ai un objet dans mon application qui représente l'une de ces lignes. Il a trois propriétés qui correspondent aux trois colonnes Attr dans la base de données.

public class Line 
{ 
    public Line(string attr1, string attr2, string attr3) 
    { 
     this.Attr1 = attr1; 
     this.Attr2 = attr2; 
     this.Attr3 = attr3; 
    } 

    public Attr1 {get; private set;} 
    public Attr2 {get; private set;} 
    public Attr3 {get; private set;} 
} 

Il existe un deuxième objet dans l'application qui stocke une collection de ces objets de ligne.

Voici la question: Quelle est la conception la plus appropriée pour référencer une ligne individuelle dans cette collection (du point de vue de l'appelant)? L'appelant doit-il être responsable du suivi de l'index de la ligne qu'il modifie, puis utiliser cet index pour modifier une ligne directement dans la collection? Ou ... il devrait être méthode (s) sur l'objet qui dit quelque chose à l'effet de:

public GetLine(string attr1, string attr2, string attr3) 
{ 
    // return the line from the collection 
} 

public UpdateLine(Line line) 
{ 
    // update the line in the collection 
} 

Nous allons avoir un débat sur notre équipe, parce que certains d'entre nous pensent qu'il est plus logique de référence une ligne en utilisant leur index interne dans la collection, et d'autres pensent qu'il n'y a aucune raison d'avoir à introduire une autre clé interne lorsque nous pouvons déjà identifier de façon unique une ligne basée sur les trois attributs.

Pensées?

+2

Je voudrais aller avec .... "changer la base de données pour ne pas avoir une clé primaire composite" si j'avais l'option et cela avait du sens. –

+0

@Fredy - Je suis avec vous à 100%. La maintenance sur des tables avec des clés étrangères groupées m'a appris que ça ne valait pas l'élégance supposée. Surtout si l'un de ces champs a des valeurs spécifiées par l'utilisateur. – overslacked

+0

Intéressant, donc vous les gars recommanderiez peut-être juste une clé entière auto-incrémentante? –

Répondre

3

Je pense que la question de base que vous rencontrez est de savoir quel contrôle l'utilisateur de votre API devrait avoir sur vos données, et ce que vous exposez exactement. Cela varie énormément en fonction de ce que vous voulez faire, et peut être soit approprié.

La question est, qui est responsable de l'information que vous souhaitez mettre à jour. De ce que vous avez posté, il semble que l'objet Ligne est responsable de l'information, et donc je recommanderais une syntaxe telle que Collection.GetLine (attr1, attr2, attr3) .UpdateX (newX) et ainsi de suite.

Cependant, il se peut que la collection ait une plus grande responsabilité à l'égard de cette information, auquel cas Collection.UpdateX (ligne, newX) aurait plus de sens (sinon, remplacez l'argument 'line' par 'attr1, attr2 , attr2 ').Troisièmement, il est possible, bien que peu probable (et rarement le meilleur design IMHO) que l'utilisateur de l'API soit responsable de l'information, auquel cas vous avez mentionné que l'utilisateur gère les index de ligne de suivi et modifie directement les informations.

5

Votre modèle d'objet doit être conçu de manière à ce qu'il soit logique pour un consommateur d'objets. Il ne devrait pas être lié au modèle de données dans la mesure du possible.

Il semble qu'il soit plus intuitif pour le consommateur d'objets de penser en termes de trois attributs. S'il n'y a pas de problèmes de performance qui disent le contraire, je laisserais le consommateur d'objets travailler avec ces attributs et ne pas le concerner avec le fonctionnement interne du stockage de données (c'est-à-dire ne pas les obliger à connaître un index interne).

0

Je préfère toujours utiliser une seule colonne d'ID de colonne, même si une clé composite peut être utilisée. Je voudrais simplement ajouter une colonne d'identité à la table et l'utiliser pour rechercher à la place. En outre, il serait plus rapide, car la requête pour une colonne int simple serait plus performante qu'une clé répartie sur trois colonnes de texte.

Avoir un utilisateur de maintenir une sorte d'index de ligne pour rechercher une ligne ne me semble pas très bon. Donc, si je devais choisir entre les deux options que vous avez posées, je voudrais utiliser la clé composite.

1

Quelle est la conception la plus appropriée lors du référencement d'une ligne individuelle dans cette collection (du point de vue d'un appelant)?

Si l'appelant est « pensée » en termes des trois attributs, je considère l'ajout d'un indexeur à votre classe de collection qui est calée sur les trois attributs, quelque chose comme:

public Line this[string attr1, string attr2, string attr3] { 
    get { 
     // code to find the appropriate line... 
    } 
} 

indexeurs sont les go-to spot pour "Comment puis-je récupérer des données de cette collection" et, OMI, sont l'accesseur le plus intuitif à toute collection.

2

Vous ne voulez pas voulez que l'objet appelant "suivre l'index de la ligne qu'il change" - jamais. Cela rend votre conception trop interdépendante, pousse les décisions d'implémentation au niveau des objets sur les utilisateurs de l'objet, rend les tests plus difficiles et peut rendre difficile le diagnostic des bogues lorsque vous mettez accidentellement à jour un objet (duplication de clé). pour mettre à jour un autre. Retour à la discipline OO: l'objet Ligne que vous renvoyez de la méthode GetLine doit agir comme une véritable "chose" de première classe. La complication, bien sûr, vient si vous modifiez l'un des champs de l'objet ligne utilisé dans le cadre de votre index. Si vous modifiez l'un de ces champs, vous ne pourrez pas trouver l'original dans la base de données lorsque vous procéderez à la mise à jour. Eh bien, c'est ce que cache des données dans les objets, non?

Voici ma suggestion, avoir trois champs intouchables dans l'objet qui correspondent à son état dans la base de données ("originalAttr1", "originalAttr2", "originalAttr3"). En outre, avoir trois propriétés ("attr1", "attr2", "attr3") qui commencent avec les mêmes valeurs que les originaux mais qui sont réglables. Vos Getters et Setters ne travailleront que sur les propriétés attr. Lorsque vous "mettez à jour" (ou effectuez d'autres actions qui remontent à la source sous-jacente), utilisez les valeurs originalAttrX comme clés (avec les contrôles d'unicité, etc.).

Cela peut sembler un peu de travail mais ce n'est rien comparé au désordre dans lequel vous allez vous lancer si vous prenez toutes ces décisions d'implémentation sur le consommateur de l'objet! Ensuite, vous aurez tous les différents consommateurs essayant de (redondant) appliquer la logique correcte d'une manière cohérente - ainsi que de nombreux autres chemins à tester. Une autre chose: ce genre de choses est fait tout le temps dans les bibliothèques d'accès aux données et est donc un modèle de codage assez commun.

0

Si le client récupère l'objet Line en utilisant trois valeurs string, c'est ce que vous transmettez à la méthode getter. À partir de ce moment, tout ce qui est nécessaire pour mettre à jour l'objet dans la base de données (tel qu'un ID de ligne unique) doit être masqué dans l'objet Line lui-même.

De cette façon, tous les détails sanglants sont cachés au client, ce qui protège le client de l'endommager, et protège également le client de toute modification future que vous pourriez apporter à l'accès dB dans l'objet Line.

Questions connexes