Avatar billede fanatic Nybegynder
01. april 2007 - 15:57 Der er 24 kommentarer og
2 løsninger

DateTime og US-format

Hej eksperter.

Jeg har et problem med DateTime i min webapplikation som benytter en simpel Access-database. I metoden herunder vil jeg gerne have indsat en ny tråd, og en post herunder, på et diskussionsboard. Metoden indsætter en ny tråd, finder derefter tråden via DateTime og opretter en post under tråden.

Det fungerer men datoen der indsættes i databasen har et US-format og ikke et DK-format. Dette forstår jeg ikke, jeg har debugget og kan se at formatet på currentDate er DK?

Fjerner jeg ## er det et DK-format der indsættes, men så fejler denne: SELECT threadId FROM Thread WHERE threadDate = '" + currentDate + "'" med typmatch blabla..exeption

Hvad kan jeg gøre for at få nedenstående til at gemme dato'er i DK-format??



public static void CreateThread(int memberId, string threadSubject, string postMessage, DateTime currentDate)
        {
            // Inserts thread.
            string sql;
            sql = "INSERT INTO Thread (threadSubject, threadCreatorId, threadDate) VALUES ('" + threadSubject + "', '" + memberId + "', #" + currentDate + "#)";
            DataControl.ExecuteNonQuery(sql);

            // Select the inserted thread.
            DataSet myData;
            sql = "SELECT threadId FROM Thread WHERE threadDate = #" + currentDate + "#";
            myData = DataControl.GetDataSet(sql);
            string threadId = myData.Tables[0].Rows[0]["threadId"].ToString();

            // Insert post in thread.
            sql = "INSERT INTO Post (postThreadId, postBody, postCreatorId, postDate ) VALUES ('" + threadId + "', '" + postMessage + "', '" + memberId + "',#" + currentDate + "#)";
            DataControl.ExecuteNonQuery(sql);
        }
Avatar billede kalp Novice
01. april 2007 - 16:04 #1
Det er også ligemeget hvordan formattet er i databasen.. når du læser dato'en skal du bare selv formattere den som du ønsker.
Avatar billede kalp Novice
01. april 2007 - 16:07 #2
du kan prøve evt. med denne kode (hvis DataControl er et command objekt)

public static void CreateThread(int memberId, string threadSubject, string postMessage, DateTime currentDate)
        {
            // Inserts thread.
            string sql;
            sql = "INSERT INTO Thread (threadSubject, threadCreatorId, threadDate) VALUES ('" + threadSubject + "', '" + memberId + "', @currentDate)";
            DataControl.Parameters.AddWithValue("@currentDate",currentDate);
            DataControl.ExecuteNonQuery(sql);

            // Select the inserted thread.
            DataSet myData;
            sql = "SELECT threadId FROM Thread WHERE threadDate = #" + currentDate + "#";
            myData = DataControl.GetDataSet(sql);
            string threadId = myData.Tables[0].Rows[0]["threadId"].ToString();

            // Insert post in thread.
            sql = "INSERT INTO Post (postThreadId, postBody, postCreatorId, postDate ) VALUES ('" + threadId + "', '" + postMessage + "', '" + memberId + "',#" + currentDate + "#)";
            DataControl.ExecuteNonQuery(sql);
        }
Avatar billede kalp Novice
01. april 2007 - 16:09 #3
for at det jeg lige nævnte skal virke ( hvis det gør )

skal // Insert post in thread.
også rettes til
 
sql = "INSERT INTO Post (postThreadId, postBody, postCreatorId, postDate ) VALUES ('" + threadId + "', '" + postMessage + "', '" + memberId + "',@currentDate)";
Avatar billede fanatic Nybegynder
01. april 2007 - 16:27 #4
Hej Kalp, tak for reply.

Da datoformatet for 1 april indsættes således i db'en "04-01-2007 14:04:23" er det ikke ligemeget. Det er jo forskel på 4 januar og 1 april.

Herunder er min klasse DataControl som blot tager sig af at åbne og lukke en databaseforbindelse.

Hvorfor laver den dette med datoen?
Jeg har da benyttet ## andre gange hvor det virker fint med indsættelse af DK-datoformat.



public class DataControl
    {
        public static DataSet GetDataSet(string SQL)
        {
            string connectionString;
            NameValueCollection appSettings;
            appSettings = System.Configuration.ConfigurationManager.AppSettings;
            connectionString = appSettings["ConnectionString"];
            OleDbConnection connection = new OleDbConnection(connectionString);
            connection.Open();
            OleDbDataAdapter adapter = new OleDbDataAdapter(SQL, connection);
            DataSet myData = new DataSet();
            adapter.Fill(myData);
            adapter.Dispose();
            connection.Close();
            return myData;
        }

        internal static void ExecuteNonQuery(string SQL)
        {
            string connectionString;
            NameValueCollection appSettings;
            appSettings = System.Configuration.ConfigurationManager.AppSettings;
            connectionString = appSettings["ConnectionString"];
            OleDbConnection connection = new OleDbConnection(connectionString);
            connection.Open();
            OleDbCommand myCommand = new OleDbCommand();
            myCommand.Connection = connection;
            myCommand.CommandText = SQL;
            myCommand.CommandType = CommandType.Text;
            myCommand.ExecuteNonQuery();
            connection.Close();
            myCommand.Dispose();
            connection.Dispose();
        }
    }
Avatar billede kalp Novice
01. april 2007 - 16:35 #5
jeg tror som sagt måske det kan løses ved brug af Parameters.AddWithValue som jeg har gjort, men det kan du selvfølgelig ikke når du har lavet din egen facade klasse:)

du kunne jo prøve at køre det direkte bare for at teste
Avatar billede fanatic Nybegynder
01. april 2007 - 16:48 #6
hmmm...det skal jeg lige tænke lidt over. Jeg kan se at jeg har det samme problem et andet sted på min side. Jeg vender tilbage....
Avatar billede neoman Novice
01. april 2007 - 16:53 #7
Jeg har lige haft tilsvarende bøvl med datoer i Access - da jeg skal have noget op at køre for at teste, så har jeg fundet en bypass som lader til at virke. Hvis du har tekststrenge som indeholder datoværdier, så kureres problemet ved at operere med formatet dd/MMM/yyyy HH:mm  Læg mærke til 3xM, som får den til at skrive måneden ud i bogstaver.

Således : datofelt.text = minDato.tostring("dd/MMM/yyyy HH:mm"). Når man så anvender
....# " & datofelt.text & " # .... i SQL sætningerne, så funker det og  datoerne i DB'en bliver i DK-format.
Avatar billede arne_v Ekspert
01. april 2007 - 16:59 #8
Man kan godt med lidt snille bruge parameters sammen med den slags database
metoder ...

Og det er den rigtige løsning at bruge parameters !
Avatar billede kalp Novice
01. april 2007 - 17:01 #9
:-)
Avatar billede neoman Novice
01. april 2007 - 17:04 #10
Arne V har helt ret - jeg bliver selv nødt til at få styr på det  en dag men skulle blot have noget op i en fart. Der er i øvrigt en interessant artikel om dato formater her :
http://www.codeproject.com/csharp/CultureInvariantDateTime.asp
Avatar billede kalp Novice
01. april 2007 - 17:21 #11
neoman >> Det kræver under 5 min af din tid at få styr på det mest basale Parameters:)
Avatar billede neoman Novice
01. april 2007 - 17:34 #12
kalp >> ikke uenig der. Jeg bruger skam også parameters lige på nær dér hvor jeg bakser med datoer. Det er såmænd mere alt det her Culture-stuff som jeg løb sur i, end parameters, så det øjeblik resten af logikken funker så SKAL jeg betvinge datoerne også :-)
Avatar billede fanatic Nybegynder
01. april 2007 - 17:39 #13
neoman>>> Vil det sige at du slet ikke bruger DateTime variabler men kun strings?

Arne>>> Vil du uddybe det du mener, forstå det ikke helt.

Er det korrekt et bruge # # i stedet for ' ' i SQL'en? Bruger jeg ' ' så indsættes datoen i DK-format.

Gør jeg det er problemet jo så bare at SELECT threadId FROM Thread WHERE threadDate = '" + currentDate + "'" fejler med datatype mismatch blabla... Er der en "work around" hertil?
Avatar billede arne_v Ekspert
01. april 2007 - 17:43 #14
et eksempel med DbWrapper GetDataSet og parameters:

using System;
using System.Data;
using System.Data.OleDb;

namespace E
{
    public class DbWrapper
    {
        private static void ProcessParams(OleDbDataAdapter da, object[] args)
        {
            for(int i = 0; i < args.Length/2; i++)
            {
                if(args[2*i+1] is int)
                {
                    da.SelectCommand.Parameters.Add((string)args[2*i], OleDbType.Integer);
                }
                else if(args[2*i+1] is decimal)
                {
                    da.SelectCommand.Parameters.Add((string)args[2*i], OleDbType.Decimal);
                }
                else if(args[2*i+1] is DateTime)
                {
                    da.SelectCommand.Parameters.Add((string)args[2*i], OleDbType.Date);
                }
                else if(args[2*i+1] is string)
                {
                    da.SelectCommand.Parameters.Add((string)args[2*i], OleDbType.VarChar);
                }
                else
                {
                    throw new DataException("Unsupported data type");
                }
                da.SelectCommand.Parameters[(string)args[2*i]].Value = args[2*i+1];
            }
        }
        public static DataSet GetDataSet(string sql, params object[] args)
        {
            OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Databases\MSAccess\Test.mdb;");
            con.Open();
            OleDbDataAdapter da = new OleDbDataAdapter(sql, con);
            ProcessParams(da, args);
            DataSet ds = new DataSet();
            da.Fill(ds);
            con.Close();
            return ds;
        }
    }
    public class MainClass
    {
        private static void Dump(DataSet ds)
        {
            foreach(DataTable dt in ds.Tables)
            {
                foreach(DataRow dr in dt.Rows)
                {
                    foreach(object o in dr.ItemArray)
                    {
                        Console.Write(" " + o);
                    }
                    Console.WriteLine();
                }
            }
        }
        public static void Main(string[] args)
        {
            DataSet ds1 = DbWrapper.GetDataSet("SELECT * FROM t1");
            Dump(ds1);
            DataSet ds2 = DbWrapper.GetDataSet("SELECT * FROM t1 WHERE f1 > @f1", "@f1", 2);
            Dump(ds2);
            DataSet ds3 = DbWrapper.GetDataSet("SELECT * FROM t1 WHERE f1 > @f1min AND f1 < @f1max", "@f1min", 2, "@f1max", 5);
            Dump(ds3);
            DataSet ds4 = DbWrapper.GetDataSet("SELECT * FROM t1 WHERE f2 > @f2", "@f2", "C");
            Dump(ds4);
            Console.ReadLine();
        }
    }
}
Avatar billede neoman Novice
01. april 2007 - 17:49 #15
fanatic - jo, men når jeg skriver DateTime til Access så bruger jeg strings. Dette begyndte jeg på efter at have brugt en hel aften på fejlfinding i min SQL og fandt en artikel på nettet (har ikke gemt den, sorry) som påpegede, at OleDBCommand som jeg tilgår Access med havde problemer med DateTime i en parameter, hvis parameteren var en del af en WHERE clause.
Avatar billede fanatic Nybegynder
01. april 2007 - 17:58 #16
Arne>> Tak, men jeg kan dog ikke se hvorfor det skulle være mere korrekt end den måd e jeg gør det på. Jeg har lagt alt databaselogik i en dll som kaldes fra GUI-delen. I sådan et tilfælde bruger man vel ikke parameters?

neoman>> Du mener altså at jeg kan gøre sådan her i min metode:

currentDate.tostring("dd/MMM/yyyy HH:mm")

# " & currentDate & " # ....
Avatar billede arne_v Ekspert
01. april 2007 - 18:00 #17
jo netop - du smider DbWrapper som hos dig hedder DataControl i din dll og kalder
den med SQL sætning og et variabel antal argument som vist i mit eksempel
Avatar billede neoman Novice
01. april 2007 - 18:01 #18
jeps ... og du skal nok bruge "+" i stedet for & (jeg bruger VB, hehe), og husk at tage sekunderne med hvis de tæller for dig; dd/MMM/yyyy HH:mm:ss
Avatar billede neoman Novice
01. april 2007 - 18:02 #19
og hvis du får Arnes wrapper til at funke med datoer så sig ventligst til. Så kan det være at jeg tyvstjæler ideen og bruger et sådant dyr også :)
Avatar billede fanatic Nybegynder
01. april 2007 - 18:08 #20
all right....tak! Jeg skal ud af døren nu, men vender lige tilbage i morgen ;-)
Avatar billede arne_v Ekspert
01. april 2007 - 18:19 #21
her er koden igen udbygger med:
  - brug af DateTime
  - ProcessParam på Command så den kan bruges i en ExecuetNonQuery

using System;
using System.Data;
using System.Data.OleDb;

namespace E
{
    public class DbWrapper
    {
        private static void ProcessParams(OleDbCommand cmd, object[] args)
        {
            for(int i = 0; i < args.Length/2; i++)
            {
                if(args[2*i+1] is int)
                {
                    cmd.Parameters.Add((string)args[2*i], OleDbType.Integer);
                }
                else if(args[2*i+1] is decimal)
                {
                    cmd.Parameters.Add((string)args[2*i], OleDbType.Decimal);
                }
                else if(args[2*i+1] is DateTime)
                {
                    cmd.Parameters.Add((string)args[2*i], OleDbType.Date);
                }
                else if(args[2*i+1] is string)
                {
                    cmd.Parameters.Add((string)args[2*i], OleDbType.VarChar);
                }
                else
                {
                    throw new DataException("Unsupported data type");
                }
                cmd.Parameters[(string)args[2*i]].Value = args[2*i+1];
            }
        }
        public static DataSet GetDataSet(string sql, params object[] args)
        {
            OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Databases\MSAccess\Test.mdb;");
            con.Open();
            OleDbDataAdapter da = new OleDbDataAdapter(sql, con);
            ProcessParams(da.SelectCommand, args);
            DataSet ds = new DataSet();
            da.Fill(ds);
            con.Close();
            return ds;
        }
    }
    public class MainClass
    {
        private static void Dump(DataSet ds)
        {
            foreach(DataTable dt in ds.Tables)
            {
                foreach(DataRow dr in dt.Rows)
                {
                    foreach(object o in dr.ItemArray)
                    {
                        Console.Write(" " + o);
                    }
                    Console.WriteLine();
                }
            }
        }
        public static void Main(string[] args)
        {
            DataSet ds1 = DbWrapper.GetDataSet("SELECT * FROM t1");
            Dump(ds1);
            DataSet ds2 = DbWrapper.GetDataSet("SELECT * FROM t1 WHERE f1 > @f1", "@f1", 2);
            Dump(ds2);
            DataSet ds3 = DbWrapper.GetDataSet("SELECT * FROM t1 WHERE f1 > @f1min AND f1 < @f1max", "@f1min", 2, "@f1max", 5);
            Dump(ds3);
            DataSet ds4 = DbWrapper.GetDataSet("SELECT * FROM t1 WHERE f2 > @f2", "@f2", "C");
            Dump(ds4);
            DataSet ds5 = DbWrapper.GetDataSet("SELECT * FROM dtest");
            Dump(ds5);
            DataSet ds6 = DbWrapper.GetDataSet("SELECT * FROM dtest WHERE d >= @d", "@d", new DateTime(2007, 4, 1));
            Dump(ds6);
            Console.ReadLine();
        }
    }
}
Avatar billede neoman Novice
04. april 2007 - 11:27 #22
Nu bruger jeg en TableAdapter på et typed DataSet, og for mig ser det ud til at være ret  ækvivalent til den ovenstående DbWrapper, men hvor jeg har fået koden serveret af VS. Er der nogen ulemper jeg har overset  ?  (Og undskyld for at sidetracke tråden lidt) :-)
Avatar billede arne_v Ekspert
08. april 2007 - 02:07 #23
koden bør også kunne bruges på et typed data set

ulemperne må være:
1) det er ikke så nemt at skifte ADO.NET provide (måske skulle DbWrapper hedde
  OleDbWrapper !)
2) der er lidt runtime overhead ved at added de parameters dynamisk
Avatar billede fanatic Nybegynder
16. april 2007 - 18:29 #24
Det er vist tid til at lukke denne.

- neoman kom med en nem og hurtig løsning.

- arneV supplerede også med en brugbar løsning.

I to deler point! Send lige et svar.

Tak til alle der deltog i debatten!!! :-)
Avatar billede arne_v Ekspert
16. april 2007 - 19:59 #25
svar
Avatar billede neoman Novice
26. april 2007 - 19:49 #26
svar
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