Vítejte na blog.vyvojar.cz Přihlásit | Registrovat | Pomoc

DRY – databáze podruhé

V první části jsem ukázal, jak zjednodušit a centralizovat práci s databázi. V tomto díle zajdu ještě dál a kód se stane ještě více obecnějším.

Connection string

Informaci o tom, jak se připojit k databázi máme nyní přímo v kódu:

using (SqlConnection connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=Names;Integrated Security=True;Pooling=False"))

 To není úplně ideální, neboť případná změna znamená zásah do kódu. Lepším řešením je přesunout tuto informaci do configuračního souboru (App.config). Změna tak znamená jen přepsání textové informace.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="NamesDatabase" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Names;Integrated Security=True;Pooling=False"/>
</connectionStrings>
</configuration>

 a kód upravíme takto:

using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["NamesDatabase"].ConnectionString))

 Změna databáze

Kód je teď více univerzální – můžeme změnit databázi, se kterou chceme pracovat. Ale co když nechceme použít MS SQL databázi, ale třeba SqLite?
Na první pohled se zdá, že budeme muset změnit kód a místo vytváření SqlConnection vytvořit objekt třídy SQLiteConnection:
 
using (SQLiteConnection connection = new SQLiteConnection(ConfigurationManager.ConnectionStrings["NamesDatabase"].ConnectionString))

a  podobné změny provést i pro command atd.

A pravděpodobně skončíme s několika metodami, jednou pro každý typ databáze:

static void WorkWithSQLDatabase(Action<SqlCommand> processCommand)
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["NamesDatabase"].ConnectionString))
{
connection.Open();

using (SqlCommand command = connection.CreateCommand())
{
processCommand(command);
}
}
}
static void WorkWithSQLITEDatabase(Action<SQLiteCommand> processCommand)
{

using (SQLiteConnection connection = new SQLiteConnection(ConfigurationManager.ConnectionStrings["NamesDatabase"].ConnectionString))
{
connection.Open();

using (SQLiteCommand command = connection.CreateCommand())
{
processCommand(command);
}
}
}

A jak je asi jasné, zase opakujeme kód, jen s mírnými změnami. Jak to napravit?
 
Obě třídy, SqlConnection a SQLiteConnection, jsou potomky abstraktní třídy DbConnection. Stačí tedy celý kód upravit takto:
 
static void WorkWithDatabase(Action<DbCommand> processCommand)
{
using (DbConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["NamesDatabase"].ConnectionString))
{
connection.Open();

using (DbCommand command = connection.CreateCommand())
{
processCommand(command);
}
}
}

a jediným problémem, který nyní máme je jak vytvořit konkrétní objekt třídy DbConnection – tedy musíme napsat kód, který rozliší s jakou databázi chceme pracovat a následně buď zavolá: new SqlConnection a nebo new SQLiteConnection.

Tento úkol často vede k řešení, kdy předáváme nějaký textový parameter a na základě jeho hodnoty rozhodujeme, který objekt vytvoříme.  Kód pak vypadá nějak takto:

if (databasename = "SQLite")
connection = new SQLiteConnection();

if (databasename = "MSSQL")
connection = new SqlConnection();

Vítejte v továrně

Předchozí kód není pěkný. Naštěstí MS na toto myslel a používá návrhový vzor Factory přesně pro tuto příležitost – v ADO.NET máme k dispozici DbProviderFactory. Tato továrna umí vyrobit objekt třídy, kterou určíme – zbývá tady jen vyřešit, kam informaci o tom, který objekt chceme vytvořit, uložíme. A pokud jsme dokázali uložit connectionString do konfiguračního souboru, bylo by  nejlepší tuto informaci uložit tamtéž.

V uzlu  connectionStringu v App.config máme možnost definovat i další atributy. Jedním z nich je i providerName. Tento atribut můžeme použít i v našem kódu a ve spolupráci s DbProviderFactory ziskat objekt té správné třídy:

public static void WorkWithDatabase(string connectionName, Action<DbCommand> processCommand)
{
string providerName = ConfigurationManager.ConnectionStrings[connectionName].ProviderName;
string connectionString = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;

DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);

using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
connection.Open();

using (DbCommand command = connection.CreateCommand())
{
processCommand(command);
}
}
}

Konfigurační soubor App.Config musí pak obsahovat:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="NamesDatabase" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Names;Integrated Security=True;Pooling=False" providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>
 
A naše hlavní metoda se pak změní takto:
static void Main(string[] args)
{
int id = default(int);
string name = string.Empty;
string commandText = string.Empty;

Action<DbCommand> find = (DbCommand command) =>
{
command.CommandText = commandText;
DbParameter dbParameter;
dbParameter = command.CreateParameter();
dbParameter.ParameterName = "@Name";
dbParameter.Value = name;
command.Parameters.Add(dbParameter);

using (DbDataReader reader = command.ExecuteReader())
{
if (!reader.HasRows)
Console.WriteLine("Sorry, nothing found");

while (reader.Read())
Console.WriteLine(reader.GetValue(0));
}
};

Console.WriteLine("Enter Id to search for:"); id = int.Parse(Console.ReadLine());
name = id.ToString();
commandText = "SELECT Name FROM Names WHERE Id=@Name";
WorkWithDatabase("NamesDatabase", find);

Console.WriteLine("Enter name to search for:"); name = Console.ReadLine();
commandText = "SELECT Id FROM Names WHERE Name=@Name";
WorkWithDatabase("NamesDatabase", find);

Console.WriteLine("Thanks for using."); Console.ReadLine();
}

 Závěr

Ukázali jsme si, jak využít konfigurační soubor k uložení informací, které můžeme změnit bez zásahu do kódu a jak napsat obecný kód, který tyto informace bude umět zpracovat. Další vylepšení budou ukázány v pokračování.

Zveřejněno 1. prosince 2010 8:40 by mstr

Upozornění na nové komentáře

Pokud chčeš dostávat upozornění emailem na změny u toho příspěvku,tak se zaregistruj zde.zde

Odebírat komentáře k tomuto příspěvku pomocí RSS

Komentář

# re: DRY – databáze podruhé

Moc pěkné. První díl jsem si našel dodatečně.... Takových článků o "eleganci" a čistotě kódu se moc nevidí. Zamyslet se a napsat kód opravdu čistě a elegantně se programátorům, alespoň těm co znám, nechce :-).

1. prosince 2010 9:52 by Jirka

# Doxycycline 20mg Internet Low Price

Order Synthroid Online No Prescription  [url=http://propecia.purchasevia.com/propecia-usa.php]Propecia Usa[/url] Can I Buy Alli In Canada

25. června 2017 2:09 by KelTeerly

# Doxycycline 20mg Internet Low Price

Order Synthroid Online No Prescription  [url=http://propecia.purchasevia.com/propecia-usa.php]Propecia Usa[/url] Can I Buy Alli In Canada

25. června 2017 2:09 by KelTeerly

# Cephalexin Drug Time

Propecia Topical Female Hair Loss  [url=http://cialonline.com]buy cialis[/url] Is Keflex Stronger Than Amoxicillin

28. června 2017 20:07 by KelTeerly

# Propecia 10mg Or 5mg

Finasteride 10mg  [url=http://buytadalaf.com]viagra cialis[/url] Coutu

6. července 2017 23:34 by KelTeerly

# Cialis Jelly Sachet

Can I Take Two Nexium Over The Counter  [url=http://pricescial.com]cialis price[/url] Acheter Viagra Generique France

7. července 2017 14:06 by ChasRegmep

# Abces Clomid

C20 Without Prescription  [url=http://cheapviapill.com]online pharmacy[/url] Preis Viagra 50 Mg

7. července 2017 14:10 by Kennglalcops

# Buy Research Tamoxifen Citrate

Levitra Gunstigster Preis  [url=http://pricescial.com]cialis buy online[/url] Viagra Online Empfehlung

10. července 2017 15:32 by KelTeerly

# Doxycycline 100mg India

Outdated Amoxicillin  [url=http://cialvia.com]cialis online[/url] Il Cialis E Curativo

12. července 2017 0:04 by Kennglalcops

# Side Effects Of Cephalexin

Amoxicilina Bacterial Infections  [url=http://onlinecial.com]cialis[/url] Baclofene Ou Aotal

17. července 2017 0:37 by KelTeerly

# Side Effects Of Cephalexin

Amoxicilina Bacterial Infections  [url=http://onlinecial.com]cialis[/url] Baclofene Ou Aotal

17. července 2017 0:38 by KelTeerly

# Comprare Viagra On Line

Amoxil 20mg Duree  [url=http://cialvia.com]online pharmacy[/url] Viagra Rezeptpflichtig Apotheke

17. července 2017 13:57 by ChasRegmep

# Orlistat 120mg Online No Script

Viagra Pour Hypertension  [url=http://pricescial.com]online pharmacy[/url] Viagra E Tachicardia

17. července 2017 14:24 by Kennglalcops

# Amoxicillin A 45 Picture

Amoxicillin Vs Augmentin For Pediatric Sinusitis  [url=http://cheapviapill.com]viagra[/url] Online Propecia Prescription Drugs

31. července 2017 17:07 by KelTeerly

Vytvoření nového komentáře

(povinný) 
povinný 
(povinný) 
Opiš čísla, která vidíš na obrázku:
 
Vyvojar.cz na prodej!