Diskuze: Problém s ukládáním datumu do databáze
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 14 zpráv z 14.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Předpokládám, že jde o zle nastavený formát data. Každopádně než text box by jsi měl asi praktičtější nějaký date picker.
Před uložením do db přetypuj na datum
DateTime datumOd;
if(!DateTime.TryParse(textboxOd.Text, out datumOd))
**{
// vypsat chybu, když to není datum
}**
else
// poslat do DB
a pak vkládej do databáze již typ DateTime. To by mělo být v pořádku.
Přetypované jsem to měl, ale zaměňuje mi to den za měsíc a naopak. Chyba bude asi ve formátu, ve kterém se to ukládá do databáze, nebo načítá zpět do text boxu.. Je to pro mně dost velký problém, protože načtené datum používám k výpočtům
A do databáze se ti to uloží správně? (Předpokládám, že ano)
Pro načtení z db používám ne moc hezkou konverzi:
tbDatumOd.Text = Convert.ToDateTime(dr["DatumOd"].ToString()).ToShortDateString();
Pokud to načítáš třeba do GridView, lze specifikovat formát, ve kterém se má datum zobrazit.
<asp:BoundField DataField="Datum" HeaderText="xxxx" DataFormatString="{0:d.M.yyyy HH:mm}" />
Podobně lze specifikovat formát při přetypování z DateTime na String.
datumDo.ToString("d.M.yyyy HH:mm")
Do databáze to ukládá špatně. Do text boxu to z databáze načte tak jak je to uloženo v databázi.
Pak budeš muset při přetypování ze stringu na datum zadat i CultureInfo.
string datum = "1.5.2014";
DateTime skutecneDatum;
System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo("cs-CZ");
skutecneDatum = DateTime.Parse(datum, ci);
Pořád stejné. Mám to napsáno takto:
private void btnInsert_Click(object sender, EventArgs e)
{
System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo("cs-CZ");
datumRevize = DateTime.Parse(txbDatum1.Text, ci);
System.Globalization.CultureInfo ci1 = new System.Globalization.CultureInfo("cs-CZ");
naslednaRevize = DateTime.Parse(txbDatum2.Text, ci1);
try
{
SqlCommand cmd1 = new SqlCommand(@"Insert Into Revize(Provozovatel, Objekt, Adresa, Odkaz, DatumRevize, NaslednaRevize, Status, CisloRevize, Ic, Predmet, Lhuta)
VALUES ( '" + txbProvozovatel.Text + "', '" + cmbObjekt.Text + "', '" + txbAdresa.Text + "', '" + odkaz + "', '" + datumRevize + "', '" + naslednaRevize + "', '" + txbStatus.Text + "', '" + txbCislo.Text + "', '" + txbIc.Text + "', '" + txbPredmet.Text + "', '" + cmbLhuta.Text + "' ) ", con);
con.Open();
cmd1.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
con.Close();
}
trvSeznam.Nodes.Clear();
try
{
SqlCommand cmd1 = new SqlCommand("SELECT * FROM Revize ", con);
con.Open();
SqlDataReader dr1 = cmd1.ExecuteReader();
while (dr1.Read())
{
var adresa = trvSeznam.Nodes.OfType<TreeNode>().FirstOrDefault(o => o.Text == dr1["Adresa"].ToString())
?? trvSeznam.Nodes.Add(dr1["Adresa"].ToString());
var subcat = adresa.Nodes.OfType<TreeNode>().FirstOrDefault(o => o.Text == dr1["Predmet"].ToString())
?? adresa.Nodes.Add(dr1["Predmet"].ToString());
subcat.Nodes.Add(dr1["CisloRevize"].ToString());
progressBar.Visible = true;
timer1.Enabled = true;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
con.Close();
}
Když pominu hrozbu SQL injekce ve tvém SQL příkazu, měl
bys k zadávání datumu používat komponenty k tomu určené, tzn.
DateTimePicker, nebo MonthCalendar, Tam se totiž datum automaticky nastaví
tak, jak má být a do DB se uloží ve správném formátu. S TextBoxem a
datumem jsou jen problémy.
v SQL příkazech používej parametry, abys předešel problémům "mezi
klávesnicí a židlí"...
Přesně jak říká Michal Štěpánek, můsíš počítat s tím že tvou aplikaci nebudeš obsluhovat jen ty. Vezmi si jak je např. jednoduché namísto
25.1.2014
napsat
25,1.2014
ty máš problém a uživatel si takového překlepu ani nemusí všimnout.
Tak že před tebou jsou dvě cesty, první-strastiplná kdy musíš myslet na
všechny tyhle možnosti a převod z textu na datum ošetřovat kódem, kupou
kódu. A nebo se vydáš druhou, jednoduší cestou a použiješ komponentu
určenou pro to co děláš a ušetříš si tak mraky práce .
Souhlasím s Michalem. Určitě při použití sql parametrizuj, Culture Info
stačí nadefinovat jednou.
(já raději na většinu věcí používám stored procedure v db, ale je to
věcí vkusu a s novými technologiemi jako EF to ztrácí význam)
takže volání je pak něco jako:
System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo("cs-CZ");
try
{
using (MujdatabazovyPomocnik dh = new MujdatabazovyPomocnik)
{
SqlParameter sqlDatumOd = new SqlParameter("@DatumOd", SqlDbType.Date);
sqlDatumOd.Value = DateTime.Parse(tbDatumOd.Text, ci);
// Nějaký další kód
dh.CallStoredProcedureNonQuery("NazevProceduryvDB", sqlDatumOd)
}
nebo ten param lze zapsat i zkráceněji:
SqlCommand command = new SqlCommand();
command.Parameters.Add("@Datum", vyrobeneDatum);
Validovat bys měl každý vstup od uživatele...
No a ještě dotaz. Sloupec v databázi máš typu DateTime?
Zkus si ten kód krokovat a dívat se, co se ti dá do proměnných při té konverzi na datum v c#. Domnívám se, že jakmile se z textu v C# vyrobí správně datum, tak se už musí i správně uložit do db...
Injekce samozřejmě upravím, mám to jenom jako testovací verzi. Co se týče DateTimePikcer i z této komponenty mi to ukládá do databáze špatně. Prohodí den s měsícem.
Jakmile jsem ošetřil injekci, databáze ukládá vše v pořádku.
no jasně. tak prima
Když dotaz skládáš VALUES ( '" + textbox.Text .. tak se to do databáze
posílá jako text i když před tím převedeš hodnotu na datum. Musí se to
pak zase převést zpátky na text a to se převede v nějakým výchozím
formátu. Kdežto, když posíláš hodnoty pomocí parametrů, tak když do
paramteru dáš hodnotu typu datetime, tak se parametr vytvoří taky typu
datetime a do db se uloží správně ve formátu datetime...
Zobrazeno 14 zpráv z 14.