IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
matesax
Tvůrce
Avatar
matesax:6.10.2012 7:54

Dobrý den,
hraji si zase s databázemi, nyní bych rád přidal data kódem (ne serepetkami). No a tak první věc - je to správně? :)

private void SetDataToDatabase(object[] parameters)
{
    using (SqlCeConnection connection = new SqlCeConnection(connectionString))
    {
        connection.Open();

        SqlCeCommand setData = connection.CreateCommand();
        setData.CommandText = "INSERT INTO RegisteredUsers (" + valuesSet.Replace("@", "") + ") VALUES (" + valuesSet +")";

        int index = 0;

        foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(valuesSet, ", "))
        {
            setData.Parameters.Add(parameterName, parameters[index]);
            index++;
        }

        setData.ExecuteNonQuery();

        setData.Parameters.Clear();
        setData.CommandText = "SELECT @@IDENTITY";

        setData.Dispose();
    }
}

Kde:

valuesSet = "[@id], [@name], [@lastname], [@dateofbirth], [@country], [@city], [@street], [@precinct], [@zipcode], [@mailingaddress], [@mobile], [@landline], [@email]"

Ale ta hlavní - jak se řeší ID? Přidat jej nemohu, vynechat také - tak jak na něj? Děkuji.

 
Odpovědět
6.10.2012 7:54
Avatar
Kit
Tvůrce
Avatar
Kit:6.10.2012 8:08

Do ID se dává NULL nebo ho vynecháš.

Vidím tam SQL injection. Pokud jsou vstupní data od uživatele, tak riskuješ.

Fungují tak i sloupce typu text? Myslím si, že ne, protože hodnoty musí být uzavřeny v apostrofech.

Obojí řeší parametrizované dotazy. Používej je. Vypadá to i lépe než slepování SQL dotazu z řetězců.

Editováno 6.10.2012 8:08
Nahoru Odpovědět
6.10.2012 8:08
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 8:46

Null jsem dával jako první:

SetDataToDatabase(new object[] { null, "Sam", "George", DateTime.Now, "Georgia", "Gradec Králové", "Bieblova", 13, 50003, "Bieblova 342, Hradec Králové 13", 732958886, 0, "[email protected]" });

Hodí:

The column name is not valid. [ Node name (if any) = ,Column name = @id ]

Data hlídám při vstupu (respektive pevně je rozděluji) - takže v tom problém nevidím - ale chtěl bych ještě umět udělat něco jako testovací řádek - přidat jej, jen když bude validní...

Píši, že tomu se chci vyhnout - totiž oni stejně jen skrývají tyto slepence... Místo 4 souborů a X řádků si jak píši vystačím s 2 metodami a to mně přijde mnohem lepší...

 
Nahoru Odpovědět
6.10.2012 8:46
Avatar
matesax
Tvůrce
Avatar
Odpovídá na matesax
matesax:6.10.2012 9:04
public partial class MainForm : Form
{
    private string connectionString = @"Data Source=|DataDirectory|\DataFileStorage.sdf", valuesSet = "[@id], [@name], [@lastname], [@dateofbirth], [@country], [@city], [@street], [@precinct], [@zipcode], [@mailingaddress], [@mobile], [@landline], [@email]";

    public MainForm()
    {
        InitializeComponent();

        SetDataToDatabase(new object[] { null, "Sam", "George", DateTime.Now, "Georgia", "Gradec Králové", "Bieblova", 13, 50003, "Bieblova 342, Hradec Králové 13", 732958886, 0, "[email protected]" }); //Testování funkčnosti
    }

    private List<List<object>> GetDataFromDatabase()
    {
        List<List<object>> rows = new List<List<object>>();

        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand getData = connection.CreateCommand();
            getData.CommandText = "SELECT " + valuesSet.Replace("@", "") + " FROM [RegisteredUsers]";

            foreach (SqlCeDataReader reader in getData.ExecuteReader())
            {
                List<object> row = new List<object>();

                foreach (object o in reader)
                    row.Add(o);

                rows.Add(row);
                reader.Close();
            }
        }

        return rows;
    }

    private void SetDataToDatabase(object[] parameters)
    {
        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand setData = connection.CreateCommand();
            setData.CommandText = "INSERT INTO RegisteredUsers (" + valuesSet.Replace("@", "") + ") VALUES (" + valuesSet +")";

            int index = 0;

            foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(valuesSet, ", "))
            {
                setData.Parameters.Add(parameterName, parameters[index]);
                index++;
            }

            setData.ExecuteNonQuery();

            setData.Parameters.Clear();
            setData.CommandText = "SELECT @@IDENTITY";

            setData.Dispose();
        }
    }
}
 
Nahoru Odpovědět
6.10.2012 9:04
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:6.10.2012 9:38

Tak z valueSet vyhoď [@id].

Testování dej přímo do databáze jako integritní omezení. Nevalidní záznam nepřijme ani z jiných aplikací, odmítne nevalidní změny záznamu a dokonce i odmítne smazat záznam, pokud by tím vznikl nevalidní záznam v jiné tabulce.

Nahoru Odpovědět
6.10.2012 9:38
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 9:48

No to jsem také zkoušel (nebrat id):

The column name is not valid. [ Node name (if any) = ,Column name = @name ]

(Pro jistotu jsem si vyobrazil ten přidávací cyklus - k parametrům dosazuje správné hodnoty.)

Editováno 6.10.2012 9:51
 
Nahoru Odpovědět
6.10.2012 9:48
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:6.10.2012 10:56

Ale to je jiná chyba. Máš tam chybnou hodnotu do @name.

Nahoru Odpovědět
6.10.2012 10:56
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 11:07

Není možné - je to ntext a dávám string...

 
Nahoru Odpovědět
6.10.2012 11:07
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:6.10.2012 11:15

Jak si jinak vysvětlíš, že si stěžuje na sloupec, který se jmenuje @name?

Nahoru Odpovědět
6.10.2012 11:15
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 11:31

OK - ale co s tím? Zkusil jsem:

SqlDbType[] types = new SqlDbType[] { SqlDbType.NText, SqlDbType.NText, SqlDbType.DateTime, SqlDbType.NText, SqlDbType.NText, SqlDbType.NText, SqlDbType.Int, SqlDbType.Int, SqlDbType.NText, SqlDbType.Int, SqlDbType.Int, SqlDbType.NText };

...

SqlCeParameter parameter = new SqlCeParameter(parameterName, types[index]);
parameter.Value =  parameters[index];
setData.Parameters.Add(parameter);

Výsledek stejný.

 
Nahoru Odpovědět
6.10.2012 11:31
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:6.10.2012 11:34

Jen tak pro zajímavost: Proč se ta proměnná jmenuje valuesSet, když je to obyčejný string? Kde vidíš tu "množinu hodnot"?

Nahoru Odpovědět
6.10.2012 11:34
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:6.10.2012 11:39

A kde máš vlastně definovánu proměnnou name a její naplnění hodnotou?

Nahoru Odpovědět
6.10.2012 11:39
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 11:43
new object[] { "Sam", "George", DateTime.Now, "Georgia", "Gradec Králové", "Bieblova", 13, 50003, "Bieblova 342, Hradec Králové 13", 732958886, 0, "[email protected]" }

Tedy to je v parametru funkce... Zde se "Sam" ukládá jako jméno...

valueSet - beru to jako sloupce - tedy nastavování hodnot sloupců...

 
Nahoru Odpovědět
6.10.2012 11:43
Avatar
Kit
Tvůrce
Avatar
Kit:6.10.2012 12:20

parameterName nabývá hodnot "[@name]", "[@lastname]", ... Skutečně jsou hranaté závorky a zavináče součástí názvu proměnné?

Nahoru Odpovědět
6.10.2012 12:20
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 13:02

Zkusil jsem je odstranit nic - tedy navíc to nezvládá parser - bez nich... Nechápu, jak jiným může chodit prostý výčet v kulatých závorkách - (name, lastname) - mě to jde jen s těmi hranatými - [name], [lastname] - jak píši, neměl by to být ten problém...

Byť je to prasárna - tuto možnost jsem zavrhl tímto:

...Replace("[", "").Replace("]", "")

A jakákoliv jiná úprava jekéhokoliv stringu nikam nevedla...

Editováno 6.10.2012 13:06
 
Nahoru Odpovědět
6.10.2012 13:02
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:6.10.2012 13:13

Protože pořád pracuješ na úrovni stringů. Pokud bys té metodě předával parametry ve formě set of tuples, problémy by nenastaly.

Nahoru Odpovědět
6.10.2012 13:13
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 13:26

No kdybych to znal - tak bych to použil. To provní cizí co jsi zmínil, to jsem si vygooglil a vyplynulo mi z toho, že se jedná o TableAdapter, DataSet - atp... Tomu se chci vyhnout - proto jsem reagoval, jak jsem reagoval. Ale tohle je pro mne již absolutní neznámá - takže kdyby jsi mi řekl o co GO, použil bych to... :) Myslím ale, že i tak by měl můj kód fungovat - respektive měl bych umět udělat to i takto (abych si mohl zvolit ze své vůle, ne kvůli schopnostem/zna­lostem).

 
Nahoru Odpovědět
6.10.2012 13:26
Avatar
Kit
Tvůrce
Avatar
Kit:6.10.2012 13:56

"set" je sada nebo množina.
"tuple" se obvykle překládá jako dvojice, ale obecně je to n-tice.

C# neznám, ale představuji si to jako množinu dvojic sloupec=>hodnota. V PHP bych to předal asi takto:

SetDataToDatabase(Array("name"=>"Sam", "lastname"=>"George"));

Správnou syntaxi pro C# si někde dohledej. V PHP z toho bez problémů vyrobím potřebný SQL dotaz. Jen bych tu metodu nazval jinak. Třeba InsertDataToDatabase(), protože to nedělá SET, ale INSERT.

Nahoru Odpovědět
6.10.2012 13:56
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:6.10.2012 14:15

No tak n-tice znám...

Nechápu tě - přiřazuji zde:

setData.Parameters.Add(parameterName, parameters[index]);// první parametr udává kam přiřadit druhý parametr
Editováno 6.10.2012 14:16
 
Nahoru Odpovědět
6.10.2012 14:15
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:7.10.2012 10:19

Tak se mi podařilo dát to dokupy:

using System;
using System.Windows.Forms;
using System.Data.SqlServerCe;
using System.Collections.Generic;

namespace WorkFISP
{
    public partial class MainForm : Form
    {
        private string connectionString = @"Data Source=|DataDirectory|\DataFileStorage.sdf", valuesSet = "@name, @lastname, @dateofbirth, @country, @city, @street, @precinct, @zipcode, @mailingaddress, @mobile, @landline, @email";

        public MainForm()
        {
            InitializeComponent();

            SetDataToDatabase(new object[] { "Sam", "George", DateTime.Now, "Georgia", "Gradec Králové", "Bieblova", 13, 50003, "Bieblova 342, Hradec Králové 13", 732958886, 0, "[email protected]" });
        }

        private List<List<object>> GetDataFromDatabase()
        {
            List<List<object>> rows = new List<List<object>>();

            using (SqlCeConnection connection = new SqlCeConnection(connectionString))
            {
                connection.Open();

                SqlCeCommand getData = connection.CreateCommand();
                getData.CommandText = "SELECT * FROM [RegisteredUsers]";

                using (SqlCeDataReader reader = getData.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        List<object> row = new List<object>();

                        for (int i = 0; i < reader.FieldCount; i++)
                            row.Add(reader.GetValue(i));

                        rows.Add(row);
                    }
                }
            }

            return rows;
        }

        private void SetDataToDatabase(object[] parameters)
        {
            using (SqlCeConnection connection = new SqlCeConnection(connectionString))
            {
                connection.Open();

                SqlCeCommand setData = connection.CreateCommand();
                setData.CommandText = "INSERT INTO RegisteredUsers (" + valuesSet.Replace("@", "") + ") VALUES (" + valuesSet +")";

                int index = 0;

                foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(valuesSet, ", "))
                {
                    setData.Parameters.AddWithValue(parameterName, parameters[index]);
                    index++;
                }

                setData.ExecuteNonQuery();
            }
        }
    }
}

Toto již nemá skoro žádný problém - tedy GetData... funguje dokonale, ovšem SetData... nepřidá řádek. Sice žádný error - a vše funguje jak má, ale ten řádek se nepřidá... :) Napadá mne, že bude problém s id sloupcem - nebo by to mohlo být něco jiného? (Nějaké návrhy na zlepšení/zkrácení?) Děkuji.

Editováno 7.10.2012 10:21
 
Nahoru Odpovědět
7.10.2012 10:19
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:7.10.2012 10:36

Ruším - funguje to dokonale - nějak nefunguje ShowData ve VS - normálně tam ten řádek je - tak jedině, kdyby se ti něco nezdálo - udělal by jsi to jinak... :) (Pardon za desinformaci.)

 
Nahoru Odpovědět
7.10.2012 10:36
Avatar
matesax
Tvůrce
Avatar
Odpovídá na matesax
matesax:7.10.2012 11:47
using System.Collections.Generic;
using System.Data.SqlServerCe;

class WorkWithDatabase
{
    private string connectionString, columns;

    public WorkWithDatabase(string connectionString, string columns)
    {
        this.connectionString = connectionString;
        this.columns = columns;
    }

    public List<List<object>> GetDataFromDatabase()
    {
        List<List<object>> rows = new List<List<object>>();

        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand getData = connection.CreateCommand();
            getData.CommandText = "SELECT * FROM [RegisteredUsers]";

            using (SqlCeDataReader reader = getData.ExecuteReader())
            {
                while (reader.Read())
                {
                    List<object> row = new List<object>();

                    for (int i = 0; i < reader.FieldCount; i++)
                        row.Add(reader.GetValue(i));

                    rows.Add(row);
                }
            }
        }

        return rows;
    }

    public void SetDataToDatabase(object[] parameters)
    {
        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand setData = connection.CreateCommand();
            setData.CommandText = "INSERT INTO RegisteredUsers (" + columns.Replace("@", "") + ") VALUES (" + columns + ")";

            int index = 0;

            foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(columns, ", "))
            {
                setData.Parameters.AddWithValue(parameterName, parameters[index]);
                index++;
            }

            setData.ExecuteNonQuery();
        }
    }

    public void UpdateDataInDatabase(int idOfUpdatingRow, object[] parameters)
    {
        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand updateData = connection.CreateCommand();
            updateData.CommandText = "UPDATE [RegisteredUsers] SET name=@name, lastname=@lastname, dateofbirth=@dateofbirth, country=@country, city=@city, street=@street, precinct=@precinct, zipcode=@zipcode, mailingaddress=@mailingaddress, mobile=@mobile, landline=@landline, email=@email WHERE id=@id";

            updateData.Parameters.AddWithValue("@id", idOfUpdatingRow);

            int index = 0;

            foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(columns, ", "))
            {
                updateData.Parameters.AddWithValue(parameterName, parameters[index]);
                index++;
            }

            updateData.ExecuteNonQuery();
        }
    }

    public void DeleteDataFromDatabase(int idOfDeletingRow)
    {
        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand removeData = connection.CreateCommand();
            removeData.CommandText = "DELETE FROM RegisteredUsers WHERE id=@id";
            removeData.Parameters.AddWithValue("@id", idOfDeletingRow);
            removeData.ExecuteNonQuery();
        }
    }
}
 
Nahoru Odpovědět
7.10.2012 11:47
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:7.10.2012 12:12

Není mi jasné, proč máš v názvech metod slovo Database, když pracuješ výhradně s tabulkou RegisteredUsers. Co když budeš chtít manipulovat s jinou tabulkou? Jak tu třídu pojmenuješ?

Třídy, objekty a metody si pojmenovávej jak chceš. Zejména pro ostatní bych však navrhl jiné názvy:

  • class RegisteredUsers
  • metody Insert, Update, Delete, ...

Nevidím žádný důvod všude opakovat slova "Work", "Data", "With" apod. Jen to prodlužuje zápis a znepřehledňuje program. Přehlednost programu je přitom velice důležitá. Vůbec nevadí, pokud jsou v různých třídách stejné názvy metod. Naopak je to velmi výhodné, protože to unifikuje přístup. Nemusím přemýšlet, jak se v této třídě jmenuje která metoda, protože pro vkládání budu mít vždy "Insert" a pro mazání "Delete".

Pod názvem "WorkWithDatabase" si nedokážu nic představit. Jenom to, že je to třída, která pracuje s nějakou databází. Takových tříd může být hromada a je nutné je nějak od sebe odlišit.

Nahoru Odpovědět
7.10.2012 12:12
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:7.10.2012 12:52
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Data.SqlServerCe;

class TableEditor
{
    private string connectionString, columns, tableName;

    public TableEditor(string connectionString, string columns, string tableName)
    {
        this.connectionString = connectionString;
        this.tableName = tableName;
        this.columns = columns;
    }

    public List<List<object>> Select()
    {
        List<List<object>> rows = new List<List<object>>();

        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand getData = connection.CreateCommand();
            getData.CommandText = "SELECT * FROM [" + tableName +"]";

            using (SqlCeDataReader reader = getData.ExecuteReader())
            {
                while (reader.Read())
                {
                    List<object> row = new List<object>();

                    for (int i = 0; i < reader.FieldCount; i++)
                        row.Add(reader.GetValue(i));

                    rows.Add(row);
                }
            }
        }

        return rows;
    }

    public void Insert(object[] parameters)
    {
        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand setData = connection.CreateCommand();
            setData.CommandText = "INSERT INTO " + tableName + " (" + columns.Replace("@", "") + ") VALUES (" + columns + ")";

            int index = 0;

            foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(columns, ", "))
            {
                setData.Parameters.AddWithValue(parameterName, parameters[index]);
                index++;
            }

            setData.ExecuteNonQuery();
        }
    }

    public void Update(int idOfUpdatingRow, object[] parameters)
    {
        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand updateData = connection.CreateCommand();

            string build = "";

            foreach (string s in Regex.Split(columns, ", "))
                build += s.Replace("@", "") + "=" + s + ", ";

            updateData.CommandText = "UPDATE [" + tableName + "] SET " + build.Substring(0, build.Length - 2) + " WHERE id=@id";

            updateData.Parameters.AddWithValue("@id", idOfUpdatingRow);

            int index = 0;

            foreach (string parameterName in Regex.Split(columns, ", "))
            {
                updateData.Parameters.AddWithValue(parameterName, parameters[index]);
                index++;
            }

            updateData.ExecuteNonQuery();
        }
    }

    public void Delete(int idOfDeletingRow)
    {
        using (SqlCeConnection connection = new SqlCeConnection(connectionString))
        {
            connection.Open();

            SqlCeCommand removeData = connection.CreateCommand();
            removeData.CommandText = "DELETE FROM " + tableName + " WHERE id=@id";
            removeData.Parameters.AddWithValue("@id", idOfDeletingRow);
            removeData.ExecuteNonQuery();
        }
    }
}
 
Nahoru Odpovědět
7.10.2012 12:52
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:7.10.2012 13:09

Hmm, tohle vypadá mnohem lépe. Navíc jsi zobecnil název tabulky, to je ještě lepší. Teď už jen pohlídat, aby byly '[' a ']' kolem každého tableName.

Přidal bych ještě metodu 'Search', která vybere jen ty záznamy, které hledám. Ovšem to by se dalo ještě dál rozšiřovat i na další metody, protože když updatuji nebo mažu záznamy, tak vždy neznám jejich id a často to ani není žádoucí.

Ještě mi není jasné, proč máš v každé metodě volání connection.Open(). Doufám, že to otvírá databázi jen napoprvé a otevřené spojení si udržuje.

Nahoru Odpovědět
7.10.2012 13:09
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:7.10.2012 13:18

Id zjišťuji jinde.

Nepřišlo mi příhodné mít celou dobu otevřené spojení - proto je to v using - stačí jen otevřít a using se o uzavření postará...

 
Nahoru Odpovědět
7.10.2012 13:18
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:7.10.2012 13:23
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Data.SqlServerCe;

class TableEditor
{
    private string connectionString, columns, tableName;
    private SqlCeConnection connection;

    public TableEditor(string connectionString, string columns, string tableName)
    {
        this.connectionString = connectionString;
        this.tableName = tableName;
        this.columns = columns;

        connection = new SqlCeConnection(connectionString);
        connection.Open();
    }

    public List<List<object>> Select()
    {
        List<List<object>> rows = new List<List<object>>();

        SqlCeCommand getData = connection.CreateCommand();
        getData.CommandText = "SELECT * FROM [" + tableName + "]";

        using (SqlCeDataReader reader = getData.ExecuteReader())
        {
            while (reader.Read())
            {
                List<object> row = new List<object>();

                for (int i = 0; i < reader.FieldCount; i++)
                    row.Add(reader.GetValue(i));

                rows.Add(row);
            }
        }

        return rows;
    }

    public void Insert(object[] parameters)
    {
        SqlCeCommand setData = connection.CreateCommand();
        setData.CommandText = "INSERT INTO [" + tableName + "] (" + columns.Replace("@", "") + ") VALUES (" + columns + ")";

        int index = 0;

        foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(columns, ", "))
        {
            setData.Parameters.AddWithValue(parameterName, parameters[index]);
            index++;
        }

        setData.ExecuteNonQuery();
    }

    public void Update(int idOfUpdatingRow, object[] parameters)
    {
        SqlCeCommand updateData = connection.CreateCommand();

        string build = "";

        foreach (string s in Regex.Split(columns, ", "))
            build += s.Replace("@", "") + "=" + s + ", ";

        updateData.CommandText = "UPDATE [" + tableName + "] SET " + build.Substring(0, build.Length - 2) + " WHERE id=@id";

        updateData.Parameters.AddWithValue("@id", idOfUpdatingRow);

        int index = 0;

        foreach (string parameterName in Regex.Split(columns, ", "))
        {
            updateData.Parameters.AddWithValue(parameterName, parameters[index]);
            index++;
        }

        updateData.ExecuteNonQuery();
    }

    public void Delete(int idOfDeletingRow)
    {
        SqlCeCommand removeData = connection.CreateCommand();
        removeData.CommandText = "DELETE FROM [" + tableName + "] WHERE id=@id";
        removeData.Parameters.AddWithValue("@id", idOfDeletingRow);
        removeData.ExecuteNonQuery();
    }
}
 
Nahoru Odpovědět
7.10.2012 13:23
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:7.10.2012 13:36

To právě není žádoucí Id zjišťovat jinde a ještě mezitím zavírat spojení s databází. Aplikace se tím velmi zpomalí. Je mnohem lepší si udržovat otevřené spojení po celou dobu běhu aplikace.

Pokud zjišťuješ Id jinde, tak velmi snadno může dojít k tzv. Race Condition neboli souběhu a tím k nekonzistenci dat. Ne že by se databáze fyzicky poškodila, ale záznam může být třeba 2× modifikován, i když by měl být modifikován pouze jednou.

Tohle je jeden z důvodů, proč nemám rád ORM frameworky. Ty jednodušší to neumí a ty složitější jsou zase pomalé.

Ještě mi tam chybí metoda pro vyhledání jednoho záznamu podle nějaké podmínky.

Nahoru Odpovědět
7.10.2012 13:36
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:8.10.2012 8:42

OK - nyní mi stačí jen ID řádku - toto ID je dostupné. (Dostanu jej při načtení tabulky.) Dále mi již stačí jen znát connection string a název tabulky - již nepotřebuji znát sloupce:

using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Data.SqlServerCe;
using System.Data;

public class TableEditor
{
    private string connectionString, columns, tableName;
    private SqlCeConnection connection;

    public TableEditor(string connectionString, string tableName)
    {
        this.connectionString = connectionString;
        this.tableName = tableName;

        connection = new SqlCeConnection(connectionString);
        connection.Open();

        string build = "";

        SqlCeCommand command = connection.CreateCommand();
        command.CommandText = "SELECT * FROM [" + tableName + "]";

        using (SqlCeDataReader reader = command.ExecuteReader())
            for (int index = 1; index < reader.FieldCount; index++)
                build += "@" + reader.GetName(index) + ", ";

        columns = build.Substring(0, build.Length - 2);
    }

    public List<List<object>> Select()
    {
        List<List<object>> rows = new List<List<object>>();

        SqlCeCommand getData = connection.CreateCommand();
        getData.CommandText = "SELECT * FROM [" + tableName + "]";

        using (SqlCeDataReader reader = getData.ExecuteReader())

            while (reader.Read())
            {
                List<object> row = new List<object>();

                for (int i = 0; i < reader.FieldCount; i++)
                    row.Add(reader.GetValue(i));

                rows.Add(row);
            }

        return rows;
    }

    public List<object> SelectRow(int selectedId)
    {
        List<object> row = new List<object>();

        SqlCeCommand getData = connection.CreateCommand();
        getData.CommandText = "SELECT * FROM [" + tableName + "]";

        using (SqlCeDataReader reader = getData.ExecuteReader())
            while (reader.Read())
                if ((int)reader.GetValue(0) == selectedId)
                    for (int i = 0; i < reader.FieldCount; i++)
                        row.Add(reader.GetValue(i));

        return row;
    }

    public void Insert(object[] parameters)
    {
        SqlCeCommand setData = connection.CreateCommand();
        setData.CommandText = "INSERT INTO [" + tableName + "] (" + columns.Replace("@", "") + ") VALUES (" + columns + ")";

        int index = 0;

        foreach (string parameterName in System.Text.RegularExpressions.Regex.Split(columns, ", "))
        {
            setData.Parameters.AddWithValue(parameterName, parameters[index]);
            index++;
        }

        setData.ExecuteNonQuery();
    }

    public void Update(int idOfUpdatingRow, object[] parameters)
    {
        SqlCeCommand updateData = connection.CreateCommand();

        string build = "";

        foreach (string s in Regex.Split(columns, ", "))
            build += s.Replace("@", "") + "=" + s + ", ";

        updateData.CommandText = "UPDATE [" + tableName + "] SET " + build.Substring(0, build.Length - 2) + " WHERE id=@id";
        updateData.Parameters.AddWithValue("@id", idOfUpdatingRow);

        int index = 0;

        foreach (string parameterName in Regex.Split(columns, ", "))
        {
            updateData.Parameters.AddWithValue(parameterName, parameters[index]);
            index++;
        }

        updateData.ExecuteNonQuery();
    }

    public void Delete(int idOfDeletingRow)
    {
        SqlCeCommand removeData = connection.CreateCommand();
        removeData.CommandText = "DELETE FROM [" + tableName + "] WHERE id=@id";
        removeData.Parameters.AddWithValue("@id", idOfDeletingRow);
        removeData.ExecuteNonQuery();
    }
}
Editováno 8.10.2012 8:43
 
Nahoru Odpovědět
8.10.2012 8:42
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:8.10.2012 9:53

Proč vlastně načítáš celou tabulku? To musí být děsně líné. Také při spolupráci více programů to může způsobit problémy. Načti si jen záznamy, které skutečně potřebuješ.

Nahoru Odpovědět
8.10.2012 9:53
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:8.10.2012 10:03

Což je celá tabulka... Mám možnost zvolit si i jen jeden řádek. A více možností nepotřebuji...

 
Nahoru Odpovědět
8.10.2012 10:03
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 31 zpráv z 31.