Avatar billede sph1nx Nybegynder
09. maj 2009 - 22:22 Der er 9 kommentarer

LINQ to SQL Rollback

Sidder og skriver på et lille jukebox projekt, i den forbindelse bruger jeg LINQ to SQL til at gemme sang informationer, stier, covers osv i en SQL 2008 database. Jeg har lavet en import funktion, og en cancel funktion til denne, men hvis jeg canceller så er der jo stadig nogle sang informationer der er gemt i databasen, kan jeg på nogen måde lave en rollback så de gemte bliver "rolled back" ?
Avatar billede arne_v Ekspert
09. maj 2009 - 22:27 #1
Transactions virker vel fint uanset om du bruger SqlCommand direkte eller LINQ for SQL.
Avatar billede Syska Mester
09. maj 2009 - 22:58 #2
Dine ting er jo ikke gemt før du kalder:

SubmitChanges() på din DataContext ...

Tror du bliver nødt til at uddybe det lidt.

// ouT
Avatar billede sph1nx Nybegynder
10. maj 2009 - 17:01 #3
Problemet ligger i at jeg kalder submitChanges for hver sang jeg har "behandlet".. Har lavet det om  så jeg først kalder submitChanges når alle sange er behandlet.. Ved ikke lige hvem der skal have point her, i kan evt dele ?
Avatar billede sph1nx Nybegynder
10. maj 2009 - 18:07 #4
Eller, det løste ikke problemet, for jeg tjekker om jeg har oprettet det album jeg prøvet at gemme, men så længe jeg ikke har kaldt submitchanges er de jo ikke oprettet, og jeg får så oprettet et album pr sang på albummet.
Avatar billede arne_v Ekspert
11. maj 2009 - 00:07 #5
Demo af transaction løsningen:

using System;
using System.Data.SqlClient;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Data.Linq.SqlClient;

namespace E
{
    [Table(Name="dummy")]
    public class Dummy
    {
        [Column(Name="id",IsPrimaryKey=true)]
        public int Id;
        [Column(Name="txt")]
        public string Txt;
    }
    public class CommitOrRollback
    {
        private SqlConnection con;
        DataContext db;
        public void Setup()
        {
            con = new SqlConnection(@"Server=ARNEPC3\SQLEXPRESS;Integrated Security=SSPI;Database=Test");
            con.Open();
            SqlCommand cre = new SqlCommand("CREATE TABLE dummy(id INTEGER, txt VARCHAR(50), PRIMARY KEY(id))", con);
            cre.ExecuteNonQuery();
            db = new DataContext(con);
        }
        public void Check()
        {
            Console.WriteLine("Data:");
            Table<Dummy> dummies = db.GetTable<Dummy>();
            foreach(Dummy d in dummies)
            {
                Console.WriteLine("  " + d.Id + " " + d.Txt);
            }
        }
        private int n = 0;
        public void Test(bool commit)
        {
            SqlTransaction tx = con.BeginTransaction();
            db.Transaction = tx;
            Dummy d1 = new Dummy();
            n++;
            d1.Id = n;
            d1.Txt = "This is test #" + n;
            db.GetTable<Dummy>().InsertOnSubmit(d1);
            db.SubmitChanges();
            Console.WriteLine("INSERT of " + d1.Id);
            Dummy d2 = new Dummy();
            n++;
            d2.Id = n;
            d2.Txt = "This is test #" + n;
            db.GetTable<Dummy>().InsertOnSubmit(d2);
            db.SubmitChanges();
            Console.WriteLine("INSERT of " + d2.Id);
            if(commit)
            {
                tx.Commit();
                Console.WriteLine("COMMIT");
            }
            else
            {
                tx.Rollback();
                Console.WriteLine("ROLLBACK");
            }
        }
        public void TearDown()
        {
            SqlCommand drp = new SqlCommand("DROP TABLE dummy", con);
            drp.ExecuteNonQuery();
            con.Close();
        }
        public static void Main(string[] args)
        {
            CommitOrRollback o = new CommitOrRollback();
            o.Setup();
            o.Check();
            o.Test(true);
            o.Check();
            o.Test(false);
            o.Check();
            o.TearDown();
            Console.ReadKey();
        }
    }
}
Avatar billede Syska Mester
11. maj 2009 - 16:53 #6
Men det løser vel ikke det problem at han vil kunne lave en rollback af mere end bare det.

Han tilføjer jo en masse data ...

Men måske bare hans logik omkring det skal laves lidt om, så det først smides ind, når man er 100% sikker på at der ikke er mere data, så er det jo nemt at lave en rollback, da man ikke har tilføjet noget endnu ...
Avatar billede sph1nx Nybegynder
11. maj 2009 - 17:04 #7
lige præcis buzz..

Her kommer det kode det drejer sig om. lille forklaring følger :
Metoden CreateTrack bliver kaldt for hvert enkelt track i en given folder, den kalder så videre til CreateOrGetArtist og CreateOrGetAlbum for at enten at få den artist samt album det drejer sig om, eller oprette det. Problemet ligger i at jeg kalder Submitchanges() i slutningen af CreateTrack, det er som sådan også fint nok, bare ikke når jeg afbryder en import så er der jo stadig blevet indsat x antal records. Laver jeg en funktion så jeg kan kalde submitChanges når jeg ved der ikke er flere filer at importere så får jeg indsat både en album og en artist record pr gang jeg kalder Create track, og det var jo ikke meningen.
     
public Artist CreateOrGetArtist(JukeDataContext JukeContext, String artistName)
        {
            Artist artist = JukeContext.Artists.SingleOrDefault(a => a.Name.ToUpper() == artistName.ToUpper());
            if (artist != null)
            {
                return artist;
            }
            artist = new Artist
            {
                Name = artistName
            };
       
            JukeContext.Artists.InsertOnSubmit(artist);
            return artist;
        }

        public Album CreateOrGetAlbum(JukeDataContext JukeContext, String AlbumName)
        {

            Album album = JukeContext.Albums.SingleOrDefault(ab => ab.Name.ToUpper() == AlbumName.ToUpper());
            if (album != null)
            {
                return album;
            }
            album = new Album
            {
                Name = AlbumName
            };
            JukeContext.Albums.InsertOnSubmit(album);


            return album;
        }
     
        public void CreateTrack(String _trackName,String _artistName, String _albumName,uint _trackNumber, String _filePath, long _duration)
        {
            if(JukeContext == null)
                JukeContext = new JukeDataContext();

                Track track = JukeContext.Tracks.SingleOrDefault(t => t.TrackName.ToUpper() == _trackName.ToUpper());

                if (track == null)
                {
                    track = new Track();
                    track.TrackName = _trackName;
                    track.Album = CreateOrGetAlbum(JukeContext, _albumName);
                    track.Artist = CreateOrGetArtist(JukeContext, _artistName);
                    track.TrackNumber = _trackNumber > 0 ? (int?)_trackNumber : null;
                    track.Filepath = _filePath;
                    track.Duration = _duration;
                    JukeContext.Tracks.InsertOnSubmit(track);
                    JukeContext.SubmitChanges();
                }
             
        }
Avatar billede arne_v Ekspert
11. maj 2009 - 17:39 #8
Det er vel lige praecis det som transaction goer her.

Mit eksempel rullede bare 2 gange gem tilbage. Men metoden kan jo rulle 1000 gange gem tilbage.
Avatar billede sph1nx Nybegynder
13. maj 2009 - 17:38 #9
Fik løst det ved at lave en seperat metode til Submitchanges, og så tjekke i DataContext.GetChangeSet om der indsat et album med det navn jeg prøver indsætte..
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



IT-JOB

VikingGenetics

Data Engineer

Udviklings- og Forenklingsstyrelsen

IAM-medarbejder

Cognizant Technology Solutions Denmark ApS

Senior Test Engineer