Avatar billede heinzdmx Nybegynder
22. november 2010 - 20:36 Der er 15 kommentarer og
1 løsning

Indsæt række hvis værdi i kolonnen med primary key ikke eksistere

Er ikke helt vant til SQL så det volder mig lidt problemer.
Bruger pt. access, men målet er at jeg vil bruge MS SQL.

Har fået insert til at virke vha. følgende:

INSERT INTO galleries (GalleriGuid, GalleriName, GalleriUploader, GalleriCreateDate) VALUES (@GalleriGuid, @GalleriName, @GalleriUploader, @GalleriCreateDate)


GalleriGuid er primary key.

Jeg vil lave det så hvis jeg har en række med GalleriGuid sat til en værdi der allerede er i databasen så skal den lade være med at indsætte det. Hvis jeg bare bruger insert så giver den en exception, der burde kunne undgås. 

Jeg skal så have gang i noget "if not exist". Men det spiller ikke helt som det skal for mig.

Her er hvad jeg har indtil videre:

IF NOT EXISTS SELECT 1 FROM galleries WHERE GalleriGuid = @GalleriGuid INSERT INTO galleries (GalleriGuid, GalleriName, GalleriUploader, GalleriCreateDate) VALUES (@GalleriGuid, @GalleriName, @GalleriUploader, @GalleriCreateDate)


Men det giver en fejl med følgende fejlmeddelser:
insert / update / delete / select var venter


PS. bruger ASP.NET C#

Håber på lidt hjælp
Avatar billede arne_v Ekspert
22. november 2010 - 20:45 #1
Sandsynligheden for en duplikat GUID er meget lille.

Jeg synes at exception er perfekt til dette formaal.

:-)
Avatar billede arne_v Ekspert
22. november 2010 - 20:46 #2
Der kan godt laves en test foerst loesning men du vil skulle haeve transaction isolation level og det vil nok paavirke performance mere end en exception en gang imellem.
Avatar billede heinzdmx Nybegynder
22. november 2010 - 21:33 #3
Det er ikke for at tjekke om der skal laves en ny GUID.

Men mere et spørgsmål om at jeg har følgende:

en handler fil bliver kaldt med en HttpPostedFile

Herefter gemmes den postede fil og jeg tilføjer en record til min database.

Her har jeg:

galleries
- GalleriGuid
- GalleriName
- osv.

images
- ImgGuid
- GalleriGuid

Hvor GalleriGuid har en relation til hinanden

Handleren får derud følgende HttpRequest:

- GalleriName
- GalleriGuid
- Og nogle flere

Grunden til at jeg ikke gør det med sessions er at den swf fil jeg bruger til upload ikke fungere så godt med sessions

Det hedder Uploadify - www.uploadify.com

Så kommer vi til det der volder mig problemer.

Nu vil jeg først tilføje en record i galleries-tabellen (men kun hvis den ikke allerede findes, i det jeg har try-catch om hele processen)

Derefter tilføjer jeg en record til images-tabellen

Muligvis ikke den bedste måde at gøre det på. Hvis der er en bedre må du da gerne komme med et forslag ;)
Avatar billede heinzdmx Nybegynder
22. november 2010 - 21:35 #4
omkring din sidste kommentar,

Hvordan skal syntaksen være til det ?

Har ikke fundet noget der lige kunne bruges på google
Avatar billede arne_v Ekspert
22. november 2010 - 22:27 #5
2 SQL sætninger (SELECT og INSERT) inden i en transaction med transaction isolation level serializable.
Avatar billede heinzdmx Nybegynder
22. november 2010 - 23:05 #6
SET TRANSACTION ISOLATION LEVEL { SERIALIZABLE }
START TRANSACTION
IF NOT EXISTS SELECT 1 FROM galleries WHERE GalleriGuid = @GalleriGuid
BEGIN
INSERT INTO galleries (GalleriGuid, GalleriName, GalleriUploader, GalleriCreateDate) VALUES (@GalleriGuid, @GalleriName, @GalleriUploader, @GalleriCreateDate)
COMMIT
END
ELSE
ROLLBACK


Giver mig samme fejl.
Kunne du komme med et eksempel der ud fra de værdier her vil virke?
Avatar billede arne_v Ekspert
22. november 2010 - 23:12 #7
Ja.

Giv mig et par timer.
Avatar billede heinzdmx Nybegynder
22. november 2010 - 23:36 #8
Har nu læst mig til at Access ikke har den store understøttelse for Transaction skrevet i SQL. I stedet skal man bruge OleDbTransation.

Med følgende kode får jeg følgende fejl:
"Hverken isolationsniveauet eller en styrkelse af det understøttes."

Det ser ud til jeg kommer nærmere..


OleDbConnection conn = new OleDbConnection(WebConfigurationManager.ConnectionStrings["ImageService"].ConnectionString);

        using (conn)
        {
            conn.Open();

            OleDbCommand cmd = conn.CreateCommand();
            OleDbTransaction myTrans;

            // Start a local transaction
            myTrans = conn.BeginTransaction(IsolationLevel.Serializable);
            // Assign transaction object for a pending local transaction
            cmd.Connection = conn;
            cmd.Transaction = myTrans;

            string sql = "";
            sql += "IF NOT EXISTS SELECT 1 FROM galleries WHERE GalleriGuid = @GalleriGuid ";
            sql += "BEGIN";
            sql += " " + "INSERT INTO galleries (GalleriGuid, GalleriName, GalleriUploader, GalleriCreateDate) VALUES (@GalleriGuid, @GalleriName, @GalleriUploader, @GalleriCreateDate)";
            sql += "END ";
            sql += "INSERT INTO images(ImgGuid, ImgPath, ImgOriginalFileName, GalleriGuid, ImgUploadDate) VALUES (@ImgGuid, @ImgPath, @ImgOriginalFileName, @GalleriGuid, @ImgUploadDate)";

            cmd.CommandText = sql;

            cmd.Parameters.AddWithValue("@GalleriGuid", galleriGuid);
            cmd.Parameters.AddWithValue("@GalleriName", galleriName);
            cmd.Parameters.AddWithValue("@GalleriUploader", galleriUploader);
            cmd.Parameters.AddWithValue("@GalleriCreateDate", uploadDate);
            cmd.Parameters.AddWithValue("@ImgGuid", imageGuid);
            cmd.Parameters.AddWithValue("@ImgPath", path);
            cmd.Parameters.AddWithValue("@ImgOriginalFileName", originalFilename);
            cmd.Parameters.AddWithValue("@ImgUploadDate", uploadDate);

            cmd.ExecuteNonQuery();

            myTrans.Commit();
        }
Avatar billede arne_v Ekspert
22. november 2010 - 23:46 #9
Min ide er ikke 1 SQL med IF men 2 SQL sætninger - en med SELECT og en med INSERT.

Så først en OleDbCommand med SELECT COUNT(*) FROM ... WHERE ..., ExecuteScalar, test på værdien, og hvis der skal indsættes så en ny OleDbCommand med INSERT ... !
Avatar billede arne_v Ekspert
22. november 2010 - 23:47 #10
Transaction isolation level er for at sikre sig mod at:

SELECT returnerer 0
en anden bruger indsætter den pågældende værdi
INSERT fejler
Avatar billede arne_v Ekspert
22. november 2010 - 23:47 #11
Men MS Access har altså nogle brgrænsninger for nu at udtrykke det diplomatisk!
Avatar billede heinzdmx Nybegynder
23. november 2010 - 00:34 #12
Jeg ved at Access har store begrænsninger. Men min computer vil af en eller anden grund ikke bruge SQL Express der ellers er installeret, og for at slippe for det bøvl, bruger jeg i en test-fase så lige Access for at kunne komme videre.



--

Jeg har fået løst problemet.

Man kan åbenbart ikke lave en Insert med kun nogle af af ens værdier. I hvertfald ikke hvis de ikke står i korrekt rækkefølge ifølge databasen og insert statement.

På den sidste af mine inserts havde jeg kun nogle af de værdier der var plads til i databasen, det kunne den ikke rigtig lide...
Da jeg tilføjede alle værdier til insert fungerede det.

Men tak for din hjælp, nu har jeg da lært lidt om SQL Transaction ;)

læg et svar, så får du point
Avatar billede arne_v Ekspert
23. november 2010 - 00:56 #13
Du kunne vælge MySQL. Med InnoDB tabeller er der support for transactions.

(bemærk dog lige licens for ADO.NET provider for MySQL)
Avatar billede arne_v Ekspert
23. november 2010 - 00:57 #14
Husk at du med transaction sog høj transaction isolation level bør kode så du håndtere lick timeouts.
Avatar billede arne_v Ekspert
23. november 2010 - 00:58 #15
Og et svar.
Avatar billede heinzdmx Nybegynder
23. november 2010 - 08:40 #16
MySQL tager jeg med i mine overvejelser
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

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