Letní akce! Lákají tě IT školení C#, Javy a PHP v Brně? Přihlas se a napiš nám do zpráv kód "BRNO 500" pro slevu 500 Kč na libovolný brněnský kurz. Lze kombinovat se slevami uvedenými u školení i použít pro více kurzů. Akce končí 28.7.

Fakturační systém v C# .NET - LocalDB a Entity Framework

C# .NET Databáze Fakturační systém v C# .NET - LocalDB a Entity Framework

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V tomto tutoriálu se naučíme vytvářet lokální databázi pro desktopovou aplikaci a její namapování na objekty pomocí Entity Frameworku. Půjde o jednoduché účetnictví. Je požadována alespoň základní znalost databází, SQL a práce s kolekcemi.

SQL CE

Do vydání Visual Studia 2013 se pro malé databáze desktopových programů používal SQL Server Compact Edition - jednoduchá verze SQL serveru tvořená pouze DLL soubory. Nepodporuje pohledy, uložené procedury, triggery a další. To nám u malé DB pro jednoduché ukládaní dat většinou stačí. Instalační soubor SQL CE má pouze kolem 2MB.

LocalDB

Od VS2013 nejde standardně vytvořit .sdf databáze pro SQL CE. Už se s CE nepočítá, i když to jde obejít pluginy. Proto si ukážeme, jak vytvořit lokální databázi LocalDB. Ta je už plnohodnotná (jako SQL server Express) a pro její spuštění na běžném PC (bez VS a SQL severu) musíme nainstalovat +- 30MB instalační soubor. Viz. tady(ENG).

Vytvoření databáze

Vytvoříme si nový konzolový projekt. Pro přidání databázového souboru máme pouze jednu možnost - soubor mdf.

Přidání databázového souboru v C# .NET

Nastavíme property databáze, aby se nám databáze přepsala pouze při změně její struktury a ne dat.

Vlastnosti databáze v C# .NET

Tvorba tabulek pro fakturační systém

Mějme tabulku faktura, která má dva cizí klíče na tabulku osoba. Ta reprezentuje dodavatele nebo odběratele.

Vytvoříme novou tabulku přes Server Explorer.

Vytvoření nové databázové tabulky

Tabulky můžeme naklikat nebo přímo napsat v SQL .

Tvorba databázových tabulek ve Visual Studio
Samotné SQL
CREATE TABLE [dbo].[Person]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY,
    [Name] NVARCHAR(100) NULL,
    [Surname] NVARCHAR(100) NOT NULL,
    [ICO] INT NULL,
    [DIC] NVARCHAR(20) NULL,
    [Street] NVARCHAR(100) NOT NULL,
    [City] NVARCHAR(100) NOT NULL,
    [PSC] INT NOT NULL,
    [Email] NVARCHAR(50) NOT NULL,
    [IsDeleted] TINYINT NOT NULL DEFAULT 0
)

CREATE TABLE [dbo].[Invoice]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY,
    [Supplier] INT NOT NULL,
    [Customer] INT NOT NULL,
    [Price] INT NOT NULL,
    [Service] NVARCHAR(200) NOT NULL,
    [Date] DATETIME NOT NULL,
    [InvoiceNumber] INT NOT NULL,
    [IsDeleted] TINYINT NOT NULL DEFAULT 0,
    CONSTRAINT [FK_Supplier] FOREIGN KEY ([Supplier]) REFERENCES [Person]([Id]),
    CONSTRAINT [FK_Customer] FOREIGN KEY ([Customer]) REFERENCES  [Person]([Id])
)

Parametr IDENTITY přidá autoinkrement primárního klíče. DEFAULT 0 nastaví defaultní hodnotu na 0. Propojení cizího klíče s primárním by vám mělo být jasné.

Entity Framework

Databázi máme hotovou. Nyní potřebujeme přistupovat k DB objektově.

Do projektu přidáme nový item ADO.NET Entity Data Model. Automaticky nám vygeneruje třídy a jejich vztahy podle DB. Je tu ještě možnost - vybrat EF DbContext Generator, ale tím se zde nebudeme zabývat (podle napsaných tříd přistupuje k DB nebo DB může i vygenerovat).

Entity Framework v C# .NET

Vybereme generování z databáze.

Entity Framework v C# .NET

Vybereme naši databázi

Entity Framework v C# .NET

Vybereme tabulky do kterých chceme přistupovat, zaškrtneme generování množných čísel u názvů objektů a klikneme na finish.

Entity Framework v C# .NET

Zobrazí se diagram naší databáze. Přejmenujeme si názvy referencí (Person1, Invoices1) ať se v tom pak vyznáme.

Entity Framework v C# .NET

Používání Entity Frameworku

Použití EF je velice jednoduché. Vytvoříme si instanci třídy DbInvoiceEntities. Ta obsahuje kolekce záznamů jednotlivých tabulek. Kolekce můžeme filtrovat, prohledávat atd. viz. zdejší tutoriály.

Přidání nového záznamu.

DbInvoiceEntities db = new DbInvoiceEntities();

Person newPerson = new Person();
newPerson.Name = "Jméno";
newPerson.Surname = "Příjmení";
newPerson.Street = "Ulice";
newPerson.City = "Město";
newPerson.PSC = 73601;
newPerson.ICO = 78321456;
newPerson.DIC = "CZ78321456";
newPerson.Email = "[email protected]";

db.Persons.Add(newPerson);
db.SaveChanges();

Pokud objektu newPerson nenastavíme nějakou not null property, při spuštění se zobrazí výjimka.

Entity Framework v C# .NET

Jednoduchý výpis v konzoli s hledáním.

Console.WriteLine("Persons: ");
foreach (Person p in db.Persons)
{
    Console.WriteLine(p.Surname + " " + p.Name + ", city: " + p.City);
}
Console.WriteLine(Environment.NewLine);

Console.WriteLine("Invoices: ");
foreach (Invoice i in db.Invoices)
{
    Console.WriteLine("Price: " + i.Price + ", date: " + i.Date);
}
Console.WriteLine(Environment.NewLine + "Search Pepa: ");

Person foundPerson = db.Persons.FirstOrDefault(p => p.Name.Contains("pepa"));
Console.WriteLine(foundPerson.Surname + " " + foundPerson.Name + ", city: " + foundPerson.City);

Závěrem

V tomto tutoriálu jsme si ukázali, jak se v C# .NET vytváří a pracuje s lokální databází. Vytvořili jsme databázi a ORM pro jednoduchý fakturační systém. V dalším tutoriálu přidáme grafické rozhraní skrze Windows Presentation Foundation.

Pokuď vám něco nefunguje nebo něčemu nerozumíte, napište do diskuze, ať to můžu v článku případně poupravit.


 

Stáhnout

Staženo 876x (10.45 MB)

 

 

Článek pro vás napsal Petr Domes (petrds)
Avatar
Jak se ti líbí článek?
12 hlasů
Programuji v .NET. Ovládám C#, .ASP, WF, WPF, SQL
Aktivity (1)

 

 

Komentáře
Zobrazit starší komentáře (42)

Avatar
Michal Štěpánek:18.1.2017 13:56

Tady to celé vzniklo tak, že zákazník chtěl "aplikaci rozumět, kontrolovat a spravovat"

Rozumět, kontrolovat a spravovat ano, ale podle mě by neměl mít přístup do databáze mimo aplikaci, protože tam může napáchat nedozírné a nevratné škody...

Odpovědět 18.1.2017 13:56
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Karel Fojtík:21.2.2017 19:58

Děkuji problém vyřešen - DB se aktualizovala ve složce Debug/Release - takže špatná DB.

 
Odpovědět 21.2.2017 19:58
Avatar
Karel Fojtík:21.2.2017 20:09

Chtěl bych se zeptat - mám program velmi podobný programu vytvořenému tady - Přes Publish jsem vytvořil ClickOnce instalační soubor. Na jiném PC kde je nainstalované VS a LocalDB je přístup k databázi bezproblémový. Na dalším PC, kde je jenom LocalDB nemůžu k databázi přistupovat a výjimka vyhazuje chybu "The underlying provider failed on Open"...Neřešil někdo tento problém - nevíte jakou komponentu na klientském PC doinstalovat?

 
Odpovědět 21.2.2017 20:09
Avatar
Odpovídá na Karel Fojtík
Michal Štěpánek:22.2.2017 7:22

Zkus zkontrolovat architekturu cílového počítače (32/64bit) a koukni se, jestli máš správně nastaven výstup z VS. Já používám x86, protože při nastavení "AnyCPU" mi to na některých strojích blblo...
Pak se ještě mrkni, zda v prográmku nepoužíváš nějakou knihovnu, kterou jsi nezakomponoval do výstupu a která případně na tom PC není...

Odpovědět 22.2.2017 7:22
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
slezak-petr
Člen
Avatar
slezak-petr:23.8.2017 14:50

Ahoj, co když potřebuji udělat View na spojení dvou / více tabulek?
A/ Udělám view v databázi a přegeneruji Entity Framework
nebo
B/ Se dělá View jako třída v C# a jak?

Mám například Tabulky/třídy Cars a Customers, které chci spojit podle Customer_ID

Odpovědět 23.8.2017 14:50
Čím víc se učím, tím víc mi přijde, že toho ještě mnoho neumím
Avatar
slezak-petr
Člen
Avatar
slezak-petr:29.10.2017 10:38

Ahoj potřeboval bych poradit s Exception, nějak nevidím chybu, zdroj chyby je tady, to je OK:

1/

try {
    db.Activities.Add(ac);
    db.SaveChanges();
}
catch (DbEntityValidationException e)
{
    if (true)
    {
        // 1.A True
        MyDbEntityValidationException ex = new MyDbEntityValidationException(e);
        Console.WriteLine(Environment.NewLine + "Err.:" + Environment.NewLine + ex.Message);
        }
    else
    {
        // 1.B False
        Console.WriteLine(Environment.NewLine + "Err.:" + Environment.NewLine + e.Message);
    }
}

Pak je třída DbEntityValida­tionException, která parsuje Exception, a vrací hezčí výsledek,
pokud ji použiji v kódu nahoře viz 1.A tak to funguje jak má

Pak je ale použití v přepsání SaveChanges(), kde očekávám, že to vybublá do kódu 1/ viz nahoře
ale ono se mi to kousne na throw newException; viz toto:

// https://stackoverflow.com/questions/7795300/validation-failed-for-one-or-more-entities-see-entityvalidationerrors-propert
// spolu s: MyDbEntityValidationException

public partial class DbUctoEntities : DbContext
{

    // obyčejná Exception vrací:
    // << Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. >>

    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException e)
        {
            // MyDbEntityValidationException parsuje Exception a vrací:
            // << Entita "Ucto.Activity" událost "Added" nastala(y) následující chyba(y) (validace):
            // Vlastnost: "Activity_abbreviation", Hodnota: "", Chyba: "Pole Activity_abbreviation je povinné." >>
            var newException = new MyDbEntityValidationException(e);
            throw newException; // <<<<<<<<<<<<<<<<<<<
        }

    }

}

Nevím proč, když mám zakomentovanou (REM) SaveChanges() tak je to OK
... nevím ...

Editováno 29.10.2017 10:40
Odpovědět 29.10.2017 10:38
Čím víc se učím, tím víc mi přijde, že toho ještě mnoho neumím
Avatar
slezak-petr
Člen
Avatar
slezak-petr:29.10.2017 10:46

Ahoj potřeboval bych poradit s Exception, nějak nevidím chybu, zdroj chyby je tady, to je OK:

1/

try {
    db.Activities.Add(ac);
    db.SaveChanges();
}
catch (DbEntityValidationException e)
{
    if (true)
    {
        // 1.A True
        MyDbEntityValidationException ex = new MyDbEntityValidationException(e);
        Console.WriteLine(Environment.NewLine + "Err.:" + Environment.NewLine + ex.Message);
    // << Entita "Ucto.Activity" událost "Added" nastala(y) následující chyba(y) (validace):
    // Vlastnost: "Activity_abbreviation", Hodnota: "", Chyba: "Pole Activity_abbreviation je povinné." >>
        }
    else
    {
        // 1.B False
        Console.WriteLine(Environment.NewLine + "Err.:" + Environment.NewLine + e.Message);
    // << Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. >>
    }
}

Pak je třída DbEntityValida­tionException, která parsuje Exception, a vrací hezčí výsledek,
pokud ji použiji v kódu nahoře viz 1.A tak to funguje jak má

Pak je ale použití v přepsání SaveChanges(), kde očekávám, že to vybublá do kódu 1/ viz nahoře
ale ono se mi to kousne na throw newException; viz toto:

// https://stackoverflow.com/questions/7795300/validation-failed-for-one-or-more-entities-see-entityvalidationerrors-propert
// spolu s: MyDbEntityValidationException

public partial class DbUctoEntities : DbContext
{

    // obyčejná Exception vrací:
    // << Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. >>

    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException e)
        {
            // MyDbEntityValidationException parsuje Exception a vrací:
            // << Entita "Ucto.Activity" událost "Added" nastala(y) následující chyba(y) (validace):
            // Vlastnost: "Activity_abbreviation", Hodnota: "", Chyba: "Pole Activity_abbreviation je povinné." >>
            var newException = new MyDbEntityValidationException(e);
            throw newException; // <<<<<<<<<<<<<<<<<<<
        }

    }

}

Nevím proč, když mám zakomentovanou (REM) SaveChanges() tak je to OK
... nevím ...

Odpovědět 29.10.2017 10:46
Čím víc se učím, tím víc mi přijde, že toho ještě mnoho neumím
Avatar
Odpovídá na slezak-petr
Ondřej Štorc:29.10.2017 12:09

Koukni se na tohle nastavení: Debug->Exceptions->Check Thrown/User-Unhandled

Odpovědět 29.10.2017 12:09
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
slezak-petr
Člen
Avatar
Odpovídá na Ondřej Štorc
slezak-petr:29.10.2017 12:20

Díky za radu ale mám české VS, a nemohu to najít, asi jsem slepý
Soubor | Upravit | Zobrazit | Projekt | Sestavit | Ladit | Tým | Nástroje | Test | Analyzovat | Okno | Nápověda

Odpovědět 29.10.2017 12:20
Čím víc se učím, tím víc mi přijde, že toho ještě mnoho neumím
Avatar
Michaal.K
Člen
Avatar
Michaal.K:Včera 12:38

Ahoj,
mám problém s přidáním dat do lokální databáze DbInvoice.mdf. Pokud přidám nového uživatele v programu přes tento kód:

DbInvoiceEntities db = new DbInvoiceEntities();

Person newPerson = new Person();
newPerson.Name = "Jméno";
newPerson.Surname = "Příjmení";
newPerson.Street = "Ulice";
newPerson.City = "Město";
newPerson.PSC = 73601;
newPerson.ICO = 78321456;
newPerson.DIC = "CZ78321456";
newPerson.Email = "[email protected]";

db.Persons.Add(newPerson);
db.SaveChanges();

a spustím aplikaci a vypíši takto data:

foreach (Person p in db.People)
{
        Console.WriteLine(p.Surname + " " + p.Name + ", city: " + p.City);
}

Tak se mi v programu zobrazí nově založený uživatel. Ale pokud ukončím aplikaci a v Server Explorer dám na připojené databázi zobrazit data tabulky Person, tak je prázdná.
Takže nově zadaný uživatel přes program není uložen v databázi.
Nevíte někdo jakto? Díky za pomoc.....

 
Odpovědět Včera 12:38
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 10 zpráv z 52. Zobrazit vše