Avatar billede mbm Nybegynder
06. februar 2010 - 14:54 Der er 16 kommentarer og
1 løsning

Retuner identity værdi ved sql insert

Hejsa

Jeg har en asp.net metode som med sql opretter en række i en tabel i en MS SQL db. Når jeg opretter rækken så bliver der i databasen automatisk oprettet en id værdi. Hvordan får jeg nemmeste denne værdi retur?


public static void CreateNewAccount(string name)
{

SqlConnection conn = new SqlConnection(DB_ConnectionHandler.GetConnectionString());

        try
        {
            string sql = @"INSERT INTO accounts
                        (name)
                        VALUES(
                          @name


            SqlCommand cmd = new SqlCommand(sql, conn);
            cmd.Parameters.AddWithValue("@name", name);
           
            conn.Open();

            cmd.ExecuteNonQuery();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
        finally
        {
            conn.Close();
        }
Avatar billede janus_007 Nybegynder
06. februar 2010 - 15:19 #1
Formentlig noget med :

cmd.Parameters.AddWithValue("@name", name);

var outParam = new SqlParameter();

outParam.Direction = ParameterDirection.ReturnValue
cmd.Parameters.Add(outParam );

Og din sql noget ala:
string sql = @"INSERT INTO accounts
                        (name)
                        VALUES(
                          @name)
;select @scope_identity"

Så vil jeg næsten tro du kan gøre sådan her:
var retVal = outParam.Value;

En anden ting jeg også lige bemærker er din try-catch, ved at throw new ødelægger du stacken, dvs. fejlen bliver pludselig meget svær at styre.

Hvis du ikke skal noget aktivt med Exception så lad være med at catch'e, det er overkill.

Wrap heller statementet ind i en using og glem finally :), ala:

using(SqlConnection conn = new SqlConnection(DB_ConnectionHandler.GetConnectionString()))
{
            string sql = @"INSERT INTO accounts
                        (name)
                        VALUES(
                          @name


            SqlCommand cmd = new SqlCommand(sql, conn);
            cmd.Parameters.AddWithValue("@name", name);
         
            conn.Open();

            cmd.ExecuteNonQuery();
...
return retVal;
        }

Og lad exception være exception :)
Læs evt. lidt her hvor jeg har beskrevet det mere detaljeret:
http://www.janusknudsen.dk/post/Exception-Handling-e28093-Oh-my-God.aspx
Avatar billede mbm Nybegynder
06. februar 2010 - 16:07 #2
Takker. Jeg har nu rettet min metode til:

using (SqlConnection conn = new SqlConnection(DB_ConnectionHandler.GetConnectionString()))
        { 
            string sql = @"INSERT INTO accounts
                    (name)
                    VALUES(
                      @name);
                      select @scope_identity";

        SqlCommand cmd = new SqlCommand(sql, conn);
        cmd.Parameters.AddWithValue("@name", name);

        var outParam = new SqlParameter();

        outParam.Direction = ParameterDirection.ReturnValue;

        conn.Open();

        cmd.ExecuteNonQuery();
         
        int retVal = (int)outParam.Value;

        return retVal;
        }


men jeg får følgende fejl:

Must declare the scalar variable "@scope_identity".

Den kender ikke til scope_identity.
Avatar billede arne_v Ekspert
06. februar 2010 - 16:12 #3
@scope_identity

->

scope_identity()
Avatar billede mbm Nybegynder
06. februar 2010 - 16:16 #4
jeg får et null retur :-(
Avatar billede arne_v Ekspert
06. februar 2010 - 16:24 #5
DU har vist også glemt:

cmd.Parameters.Add(outParam );
Avatar billede mbm Nybegynder
06. februar 2010 - 22:47 #6
Ja det manglede jeg vist, men nu får jeg et 0 hvor jeg havde forventet 4 hvilket er int værdien for nøglen på den netop oprettede række.
Avatar billede janus_007 Nybegynder
06. februar 2010 - 23:47 #7
Okay... og hvis du selv eksekverer SQL'en igennem SSMS hvad får du så? Er du sikker på der er en primær nøgle
Avatar billede mbm Nybegynder
07. februar 2010 - 01:06 #8
Ja det er med sikkerhed den primære nøgle.
Afvikler jeg mit script direkte i database manageren så jeg det rigtige resultat.
Avatar billede arne_v Ekspert
07. februar 2010 - 03:45 #9
Ah.

select scope_identity()

returnerer ikke en out parameter men et result set.

Derfor skal der bruges ExecuteScalar eller ExecuteReader ikke ExecuteNonQuery.

Eksempel:

using System;
using System.Data;
using System.Data.SqlClient;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            using(SqlConnection con = new SqlConnection(@"Server=ARNEPC3\SQLEXPRESS;Integrated Security=SSPI;Database=Test"))
            {
                con.Open();
                SqlCommand cre = new SqlCommand("CREATE TABLE autofun (id INTEGER IDENTITY PRIMARY KEY, txt VARCHAR(50))", con);
                cre.ExecuteNonQuery();
                SqlCommand ins = new SqlCommand("INSERT INTO autofun(txt) VALUES(@txt); SELECT SCOPE_IDENTITY()", con);
                ins.Parameters.Add("@txt", SqlDbType.VarChar, 50);
                for(int i = 0; i < 10; i++)
                {
                    ins.Parameters["@txt"].Value = "Text #" + i;
                    int autoid = (int)(decimal)ins.ExecuteScalar();
                    Console.WriteLine(autoid);
                }
                SqlCommand drp = new SqlCommand("DROP TABLE autofun", con);
                drp.ExecuteNonQuery();
            }
            Console.ReadKey();
        }
    }
}
Avatar billede arne_v Ekspert
07. februar 2010 - 03:51 #10
Men jeg ville nok overveje:

using System;
using System.Data;
using System.Data.SqlClient;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            using(SqlConnection con = new SqlConnection(@"Server=ARNEPC3\SQLEXPRESS;Integrated Security=SSPI;Database=Test"))
            {
                con.Open();
                SqlCommand cre = new SqlCommand("CREATE TABLE autofun (id INTEGER IDENTITY PRIMARY KEY, txt VARCHAR(50))", con);
                cre.ExecuteNonQuery();
                SqlCommand ins = new SqlCommand("INSERT INTO autofun(txt) VALUES(@txt)", con);
                ins.Parameters.Add("@txt", SqlDbType.VarChar, 50);
                SqlCommand sel = new SqlCommand("SELECT @@IDENTITY", con);
                for(int i = 0; i < 10; i++)
                {
                    ins.Parameters["@txt"].Value = "Text #" + i;
                    ins.ExecuteNonQuery();
                    int autoid = (int)(decimal)sel.ExecuteScalar();
                    Console.WriteLine(autoid);
                }
                SqlCommand drp = new SqlCommand("DROP TABLE autofun", con);
                drp.ExecuteNonQuery();
            }
            Console.ReadKey();
        }
    }
}

multistatement eksekvering bliver nok blokeret på et tidspunkt.
Avatar billede mbm Nybegynder
07. februar 2010 - 10:09 #11
Tak til janus_007 og arne_v. Jeg fik lært noget ny af jer begge. arne_v's svar gav dog løsningen på mit problem :-)

arne_v << Hvis du laver et svar så får du lidt points.
Avatar billede janus_007 Nybegynder
07. februar 2010 - 13:05 #12
mjaaa. ExecuteNonQuery er tiltænkt at arbejde med output params, jeg må dog indrømme at det er mange år siden jeg sidst har brugt den :)

Nu ved lidt eftertanke er det nok mere ved stored procedure OUTPUT at mit forslag kan lade sig gøre :)

Well... men arnes virker jo fint :)
Avatar billede mbm Nybegynder
07. februar 2010 - 18:18 #13
De eksempler jeg fandt online var nemlig også med Stored procedure men det har jeg fravalgt i denne løsning.
Avatar billede janus_007 Nybegynder
07. februar 2010 - 19:56 #14
Hvis du har mulighed for det burde du overveje Linq To Sql eller Linq To Entities istedet.
Avatar billede arne_v Ekspert
08. februar 2010 - 02:30 #15
SP og out parameter passer perfekt til hinanden.

Eksempel:

using System;
using System.Data;
using System.Data.SqlClient;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            using(SqlConnection con = new SqlConnection(@"Server=ARNEPC3\SQLEXPRESS;Integrated Security=SSPI;Database=Test"))
            {
                con.Open();
                SqlCommand cre = new SqlCommand("CREATE TABLE autofun (id INTEGER IDENTITY PRIMARY KEY, txt VARCHAR(50))", con);
                cre.ExecuteNonQuery();
                SqlCommand cresp = new SqlCommand("CREATE PROCEDURE usp_ins_auto @txt VARCHAR(50), @id INTEGER OUTPUT AS INSERT INTO autofun(txt) VALUES(@txt); SELECT @id = SCOPE_IDENTITY()", con);
                cresp.ExecuteNonQuery();
                SqlCommand ins = new SqlCommand();
                ins.CommandText = "usp_ins_auto";
                ins.CommandType = CommandType.StoredProcedure;
                ins.Connection = con;
                SqlParameter p1 = new SqlParameter();
                p1.ParameterName = "@txt";
                p1.DbType = DbType.String;
                p1.Size = 50;
                p1.Direction = ParameterDirection.Input;
                ins.Parameters.Add(p1);
                SqlParameter p2 = new SqlParameter();
                p2.ParameterName = "@id";
                p2.DbType = DbType.Int32;
                p2.Direction = ParameterDirection.Output;
                ins.Parameters.Add(p2);
                for(int i = 0; i < 10; i++)
                {
                    ins.Parameters["@txt"].Value = "Text #" + i;
                    ins.ExecuteNonQuery();
                    int autoid = (int)p2.Value;
                    Console.WriteLine(autoid);
                }
                SqlCommand drpsp = new SqlCommand("DROP PROCEDURE usp_ins_auto", con);
                drpsp.ExecuteNonQuery();
                SqlCommand drp = new SqlCommand("DROP TABLE autofun", con);
                drp.ExecuteNonQuery();
            }
            Console.ReadKey();
        }
    }
}
Avatar billede arne_v Ekspert
08. februar 2010 - 02:30 #16
og et svar fra mig
Avatar billede mbm Nybegynder
08. februar 2010 - 08:43 #17
Jeg har ikke så megen erfaring med Linq endnu men bruger der når jeg skal søge i List<>'er.
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