Avatar billede globen Nybegynder
20. februar 2010 - 16:44 Der er 8 kommentarer og
1 løsning

SqlException: Error converting data type nvarchar to int.

Hej prøver at kalde en SqlServer stored procedure fra C#, men bliver mødt med en SqlException når jeg kalder ExecuteNonQuery() på mit SqlCommand object. Jeg har gået alle mine parametre igennem flere gange og må efterhånden erkende at jeg har set mig helt blind på hvad der forsager denne exception. Er der nogen der kan hjælpe?




########################################################
C# kode:
########################################################
public class PAccountGroups_GetById
    {
        public PAccountGroups_GetByIdResult ExecuteNonQuery(int @iAccountGoupsId, object transaction)
        {
            SqlConnection conn = null;
            SqlCommand cmd = null;
            try
            {
                conn = new SqlConnection(SqlConnectionString.ConnectionString);
                conn.Open();
                cmd = conn.CreateCommand();
                if (transaction != null)
                    cmd.Transaction = (SqlTransaction)transaction;
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandText = "pAccountGroups_GetById";

                SqlParameter param0Input = new SqlParameter("@iAccountGoupsId", DbType.Int32);
                param0Input.Direction = ParameterDirection.Input;
                param0Input.Value = @iAccountGoupsId;
                cmd.Parameters.Add(param0Input);

                SqlParameter param0InputOutput = new SqlParameter("@oAccountType", DbType.Int32);
                param0InputOutput.Direction = ParameterDirection.InputOutput;
                cmd.Parameters.Add(param0InputOutput);

                SqlParameter param1InputOutput = new SqlParameter("@oName", DbType.String);
                param1InputOutput.Direction = ParameterDirection.InputOutput;
                cmd.Parameters.Add(param1InputOutput);

                SqlParameter param2InputOutput = new SqlParameter("@oDescription", DbType.String);
                param2InputOutput.Direction = ParameterDirection.InputOutput;
                cmd.Parameters.Add(param2InputOutput);

                SqlParameter param3InputOutput = new SqlParameter("@oAccountGroupsId", DbType.Int32);
                param3InputOutput.Direction = ParameterDirection.InputOutput;
                cmd.Parameters.Add(param3InputOutput);

                cmd.ExecuteNonQuery();
                PAccountGroups_GetByIdResult result = new PAccountGroups_GetByIdResult();
                result.OutputParameters.@oAccountType = (int)cmd.Parameters["@oAccountType"].Value;
                result.OutputParameters.@oName = (string)cmd.Parameters["@oName"].Value;
                result.OutputParameters.@oDescription = (string)cmd.Parameters["@oDescription"].Value;
                result.OutputParameters.@oAccountGroupsId = (int)cmd.Parameters["@oAccountGroupsId"].Value;

                return result;
            }
            catch
            {
                if (cmd != null)
                    cmd.Dispose();
                if (conn != null)
                    try { conn.Close(); } catch {  }
                throw;
               
            }
            finally
            {
                cmd.Dispose();
                conn.Close();
            }
        }
    }

    public class PAccountGroups_GetByIdResult
    {
        public PAccountGroups_GetByIdResult() { OutputParameters = new PAccountGroups_GetByIdOutputParams(); }
        public PAccountGroups_GetByIdOutputParams OutputParameters { get; set; }
    }

    public class PAccountGroups_GetByIdOutputParams
    {
        public int @oAccountType { get; set; }
        public string @oName { get; set; }
        public string @oDescription { get; set; }
        public int @oAccountGroupsId { get; set; }
    }

########################################################
SqlServer Stored Procedure
########################################################
/****** Object:  StoredProcedure [dbo].[pAccountGroups_GetById]    Script Date: 02/20/2010 16:29:32 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER OFF
GO


CREATE PROCEDURE [dbo].[pAccountGroups_GetById]
    @iAccountGoupsId        INT,
    @oAccountType            INT OUT,
    @oName                    NVARCHAR(255) OUT,
    @oDescription            NVARCHAR(4000) OUT,
    @oAccountGroupsId        INT OUT
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
   
        SELECT    @oAccountGroupsId = AccountGroupsId,
                @oAccountType = AccountType,
                @oDescription = [Description],
                @oName = Name               
        FROM    tAccountGroups
        WHERE    AccountGroupsId = @iAccountGoupsId

        IF @oAccountGroupsId IS NULL
        BEGIN
            RAISERROR ('The AccountGroup could not be found.',18,1)
        END

    END TRY
    BEGIN CATCH

        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = ERROR_MESSAGE(),
              @ErrorSeverity = ERROR_SEVERITY(),
              @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage,
                  @ErrorSeverity,
                  @ErrorState
                  );
    END CATCH
   
END

GO
Avatar billede arne_v Ekspert
20. februar 2010 - 17:25 #1
SELECT    @oAccountGroupsId = AccountGroupsId,
                @oAccountType = AccountType,
                @oDescription = [Description],
                @oName = Name             
        FROM    tAccountGroups
        WHERE    AccountGroupsId = @iAccountGoupsId

passer kolonne typerne i tabellen med typerne i din SP ?
Avatar billede arne_v Ekspert
20. februar 2010 - 17:26 #2
Generelt vil jeg anbefale at angive længde på parameters af typerne VARCHAR og NVARCHAE.
Avatar billede janus_007 Nybegynder
20. februar 2010 - 19:25 #3
globen -> Det er nu heller ikke den bedste måde at hente data ud på, har du det som et krav fra en evt. kunde at du skal bruge sprocs til selects?
Avatar billede globen Nybegynder
21. februar 2010 - 00:33 #4
Arne ->

Ja, datatyperne i de kolonner der bliver selected er af samme type og størrelse som procedures parametre. God pointe med varchar længde. Jeg havde set at der var en overloaded constructor af SqlParamterer hvor dette kunne angives.

Janus ->

Hvad mener du når du siger det ikke den bedste måde at hente data ud på? Er det fordi du mener at det performer dårligt? Det er ikke et krav jeg har fået stillet, men måden jeg selv har valgt. Jeg har på det sidste gjort stort brug af stored procedures, og er derfor i gang med at skrive en applikation der kan generere den nødvendige C# kode til at kalde disse. Ovenstående C# klasser er genereret på baggrund af proceduren, men som det fremgår af denne tråd er det ikke kørende endnu.. :s
Avatar billede globen Nybegynder
21. februar 2010 - 01:11 #5
*Jeg havde IKKE set at der var en overloaded...
Avatar billede janus_007 Nybegynder
21. februar 2010 - 01:51 #6
Hej globen

Man kan lægge sin logik 2 steder, enten i applikationen eller på db-niveau vha. sprocs. Problemet med sprocs er ofte at de bliver misbrugt til selects hvor den ene parameter skal tweakes og der skal være flere sprocs til samme udtryk med med et variabelt antal parameters; langtfra optimalt imho. Misforstå mig ikke, jeg synes sprocs er geniale (tjek min profil :) ) og jeg ville absolut ikke undvære dem, men alt med måde!

Som du selv sidder nu, med problemer omkring parameters, så forestil dig problemstillingen igen hvis / når sproc'en skal ændres lidt.
Hvis jeg lige skal bedømme din kode, så er din sproc måske lige for overgjort/ besværliggjort. Du binder forretningslogik op på account group, en check som kunne være gjort i dit data access lag, hvad nu hvis account typen heller ikke kunne findes osv. osv. Det er muligt det ikke er sådan lige nu, men som vi alle ved i udvikling, så har tingene det med at ehhmm "udvikle" sig :)
Og så skal du rette dels din sproc men også din applikation, igen ikke videre optimalt.
Derudover har du noget try-catch som umiddelbart ikke giver mening, kan være det senere skal udvides, men igen... forretningslogikken forplumrer renheden i sproc'en.

Mht. performance, så performer en sproc nu ikke nødvendigvis bedre en ren Sql, i enkelte tilfælde snarere tværtimod.

Selve C# koden bruger du også tid på at skrive og debugge, jeg går udfra du har et datalag, så når du modtager et resultat fra sproc'en skal du ligeledes mappe det videre, ofte 1 til 1.
Når du arbejder med datalag er der ingen grund til at anvende sproc's, så er du bedre tjent med bare at skrive sql'en direkte i dal'en og så evt. hvis du ønsker en abstraktion til dine tabeller så opretter du views og bruger dem i din Sql istedet for at refererer direkte til tabellen. Ligeledes vil det også gøre en evt. deploy meget nemmere, da man ikke er afhængig af 300 små sprocs på db'en.

Alt i alt ville man have opnået en mere forståelig og mere vedligeholdelsesvenlig kode som ville fylde 5-6 linjer istedet.

Jeg har selv været stormisbruger af sprocs,  min opfattelse har dog ændret sig efter mange års filosofering over hvorfor vi gør som vi gør - er det i virkeligheden bare fordi "sådan plejer man..."

Nu er der så kommet Linq to Sql / Entities, hvilket kun gør det hele endnu nemmere, da du totalt undgår dine casts og iterationer, men det er en anden snak :)
Avatar billede globen Nybegynder
23. februar 2010 - 13:34 #7
I forbindelse med at jeg har foretaget andre ændringer er dette problem forsvundet. Jeg gider ikke bruge kræfter på at genskabe det, så jeg lukker spørgsmålet.

Tak for jeres tid. Og tak fordi du ville dele dine holdninger med mig Janus. Det vil jeg tage til eftertanke.

- Globen
Avatar billede Syska Mester
23. februar 2010 - 14:06 #8
God skik ville nok være at give Janus_007 lidt point.
Avatar billede globen Nybegynder
23. februar 2010 - 14:43 #9
Det ville jeg også mene. Jeg troede dog at normen herinde var anderledes, da min erfaring siger at folk takker nej, såvidt de ikke har besvaret det spørgsmål der var oprettet.

Men jeg giver gerne points for folks tid. Men kan jeg så genindsætte points på dette spørgsmål, eller skal jeg starte et nyt? Og vil det i så fald ikke være dårlig skik? Altså at "spamme" eksperten med ikke-fagrelevante spørgsmål...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester