1
votes

Problème avec la base de données - Clé étrangère toujours nulle (T-SQL)

Mon problème est peut-être un peu long à décrire car le projet sur lequel nous travaillons est un peu plus grand, mais je vais essayer d'être aussi précis que possible.

Fondamentalement, nous développons une gestion des plaies basée sur le Web ( partie d'un projet pour l'université) où l'utilisateur peut saisir des blessures et définir des informations supplémentaires telles que la taille, la consistance, télécharger une photo, choisir l'emplacement, .... Toutes ces informations doivent être stockées dans une base de données (nous travaillons avec MS SQL Studio et Visual Studio 2017) où l'utilisateur peut également les récupérer ultérieurement pour les visualiser sur le module.

Le problème auquel nous sommes confrontés maintenant, si nous voulons montrer une blessure à une blessure spéciale à l'utilisateur, nous ne pouvons pas faire fonctionner les clés étrangères. Nous pouvons filtrer via le numéro de cas (qui fonctionne) mais nous ne pouvons pas filtrer les informations sur la plaie par l'ID de la plaie (chaque plaie reçoit un identifiant unique) - donc si nous choisissons une plaie, nous obtenons toujours des informations sur TOUTES les plaies qui sont stockés pour le casenr donné.

Ceci est notre "table principale" où chaque blessure reçoit un identifiant unique qui est également une colonne d'identité ascendante:

CONSTRAINT [FK_epadoc_mod_wound_details] FOREIGN KEY ([wound_id])
REFERENCES [dbo].[epadoc_mod_wound_progress] ([progress_id])

Si l'utilisateur entre les informations et clique sur "Suivant", une fonction est appelée dans le code derrière lequel remplit la table:

_db.SaveWoundProgress(wound_length, wound_width, wound_depth, woundArea, woundEdge, woundStatus, painStatus, itchStatus);

Cela conduit à notre base de données, où nous avons nos requêtes pour la base de données, dans ce cas:

 public void SaveWoundProgress(int woundLength, int woundWidth, int woundDepth, string woundSurrounding, string woundConsistence, string woundState, string woundPainScale, string woundItch)
        {
            var table = ConfigurationManager.AppSettings["woundProgressTable"];
            var insertQuery = "INSERT INTO " + table + "(wound_length,wound_width,wound_depth, wound_surrounding, wound_consistence, wound_state, wound_painscale, wound_itch) VALUES (@woundLength, @woundWidth, @woundDepth, @woundSurrounding, @woundConsistence, @woundState, @woundPainScale, @woundItch)";


            var cmd = new SqlCommand(insertQuery);

            cmd.Parameters.AddWithValue("@woundLength", woundLength);
            cmd.Parameters.AddWithValue("@woundWidth", woundWidth);
            cmd.Parameters.AddWithValue("@woundDepth", woundDepth);
            cmd.Parameters.AddWithValue("@woundSurrounding", woundSurrounding);
            cmd.Parameters.AddWithValue("@woundConsistence", woundConsistence);
            cmd.Parameters.AddWithValue("@woundState", woundState);
            cmd.Parameters.AddWithValue("@woundPainScale", woundPainScale);
            cmd.Parameters.AddWithValue("@woundItch", woundItch);
            var db = DatabaseController.getDataBaseController();

            try
            {
                var sqlcmd = db.executeSQL(cmd);
            }
            catch (SqlException e)
            {

            }
        }

La connexion etc. est dans une classe de gestionnaire de base de données qui n'est pas pertinente pour le moment. p >

Jusque-là, cela fonctionne bien. Mais maintenant nous avons un deuxième tableau pour plus d'informations sur la plaie, qui est également rempli au prochain clic, lié à ce tableau:

CREATE TABLE [dbo].[epadoc_mod_wound_progress] (
    [progress_id]       INT           IDENTITY (1, 1) NOT NULL,
    [wound_length]      INT           NULL,
    [wound_width]       INT           NULL,
    [wound_depth]       INT           NULL,
    [wound_surrounding] VARCHAR (500) NULL,
    [wound_consistence] VARCHAR (500) NULL,
    [wound_state]       VARCHAR (200) NULL,
    [wound_painscale]   VARCHAR (MAX) NULL,
    [wound_itch]        VARCHAR (MAX) NULL,
    PRIMARY KEY CLUSTERED ([progress_id] ASC)

Avec la MÉTHODE INSERT: p>

 public void SaveWoundDetails(int casenr, string woundType, int decuGrade, string woundComment, DateTime timeReal, DateTime timeGiven , string user)
        {
            var table = ConfigurationManager.AppSettings["woundDetailsTable"];
            var insertQuery = "INSERT INTO " + table + "(casenumber, wound_type, decuGrade, wound_comments, wound_timeReal, wound_timeGiven, username) VALUES (@casenr, @woundType, @decuGrade, @woundComment, @timeReal, @timeGiven, @user)";


            var cmd = new SqlCommand(insertQuery);

            cmd.Parameters.AddWithValue("@casenr", casenr);
            cmd.Parameters.AddWithValue("@woundType", woundType);
            cmd.Parameters.AddWithValue("@decuGrade", decuGrade);
            cmd.Parameters.AddWithValue("@woundComment", woundComment);
            cmd.Parameters.AddWithValue("@timeReal", timeReal);
            cmd.Parameters.AddWithValue("@timeGiven", timeGiven);
            cmd.Parameters.AddWithValue("@user", user);
            var db = DatabaseController.getDataBaseController();

            try
            {
                var sqlcmd = db.executeSQL(cmd);
            }
            catch (SqlException e)
            {

            }
        }

Et la méthode

 _db.SaveWoundDetails(casenr, woundValue, decu, additional_info, realTime, givenBackDocDate, user);

qui s'exécute juste après la méthode mentionnée ci-dessus.

Je sais comment créer des clés étrangères entre deux tables, mais tout ce que nous avons essayé a échoué - si nous essayons de l'exécuter avec un jeu de clés étrangères qui n'est PAS NULL, nous obtenons une exception nulle.

Exemple de quoi nous avons essayé:

    [wound_id]          INT           IDENTITY (1, 1) NOT NULL,
    [wound_type]        VARCHAR (500) NULL,
    [wound_description] VARCHAR (500) NULL,
    [decuGrade]         INT           NULL,
    [wound_comments]    VARCHAR (500) NULL,
    [wound_timeReal]    DATETIME      NULL,
    [wound_timeGiven]   DATETIME      NULL,
    [casenumber]        INT           NULL,
    [username]          VARCHAR (50)  NULL,
    PRIMARY KEY CLUSTERED ([wound_id] ASC)
);

Si nous avons défini une clé étrangère comme celle-ci, cela n'a pas fonctionné.

Nous sommes arrivés à la conclusion que ce doit être un problème la pile d'appels lorsque les deux méthodes sont exécutées - mais nous ne savons pas comment nous pouvons le résoudre. Peut-être que nous devons définir la clé étrangère dans la requête INSERT en tant que variable explicite?

Ce que nous voulons, c'est que l'ID de la plaie de la table de détails soit pris comme clé étrangère de la table de progression afin qu'une plaie peut être modifiée plus tard (par exemple si elle guérit, l'utilisateur peut ré-entrer la nouvelle taille, etc.) et nous pouvons filtrer par ID pour montrer juste UNE plaie au patient et pas toutes les plaies en même temps si vous cliquez sur une blessure spécifique.

Malheureusement, je ne suis pas le grand expert des bases de données, donc j'espère que vous pourrez suivre mes explications :).

Merci pour toute aide!

p>


1 commentaires

Supprimez tous ces blocs catch {} qui masquent les erreurs. À l'heure actuelle, vous ne savez pas si l'une de ces instructions réussit ou génère une erreur. catch {} ne supprime pas les erreurs ni ne rend votre code plus robuste, cela signifie que vous n'avez aucun moyen de savoir si cela fonctionne même


3 Réponses :


3
votes

Votre epadoc_mod_wound_progress doit inclure une colonne [wind_id] INT NOT NULL . C'est ce sur quoi votre clé étrangère doit être construite pour qu'une blessure puisse avoir plusieurs progrès de blessure. Ensuite, dans votre instruction d'insertion, vous insérerez le wind_id qui génère dans la table blessureDetail l'insert de table dans epadoc_mod_wound_progress .


3 commentaires

Hé, tout d'abord - merci pour votre réponse! Je dois donc d'abord obtenir l'identifiant via l'instruction SELECT et l'entrer ensuite avec INSERT? Ou y a-t-il un moyen plus simple? :)


Ce lien est votre meilleure stratégie: stackoverflow.com/questions/18373461/... L'utilisation de executescalar avec une insertion renvoie l'ID. Je mettrais à jour votre méthode SaveWoundDetails pour renvoyer int .


Ouais, je l'ai trouvé entre-temps, j'ai utilisé SCOPE_IDENTITY () pour passer l'ID à l'autre table :) - merci pour votre aide, cela fonctionne maintenant! :)



1
votes

J'ai essayé d'ajouter un commentaire mais je n'ai pas 50 points de réputation.

D'après ce que je peux voir, je suppose que vous essayez d'établir une relation un à plusieurs entre la "table principale" et la table "epadoc_mod_wound_progress", n'est-ce pas?

Si c'est le cas, vous ne semblez pas avoir de champ dans la table "epadoc_mod_wound_progress" qui stocke l'id de blessure, comment essayez-vous de créer une clé étrangère si vous ne stockez pas l'id de blessure?

Suggérer que la clé primaire de la table epadoc_mod_wound_progress est une clé concaténée de wind_id et de progress_id, avec wind_id étant également la clé étrangère reliant la table principale.


0 commentaires

1
votes

Dans la table epadoc_mod_wound_progress , il doit y avoir une colonne blessure_id INT NOT NULL faisant office de clé étrangère.

La contrainte doit également être ajoutée à la table de clé étrangère, c'est-à-dire le tableau du côté n de la relation 1 à n . En supposant que le nom de la table principale est epadoc_mod_wound_details (vous ne l'avez pas montré):

ALTER TABLE dbo.epadoc_mod_wound_progress
ADD CONSTRAINT FK_progress_details FOREIGN KEY (wound_id)
REFERENCES dbo.epadoc_mod_wound_details (wound_id)
ON DELETE CASCADE

Aussi, en ajoutant ON DELETE CASCADE la progression d'un détail de plaie sera automatiquement supprimée lorsque vous supprimez le détail de la plaie.


0 commentaires