wtorek, 28 sierpnia 2012

Mapowanie typów SqLite na typy .Net

Mapując tabelę stworzoną w SqLite na obiekt w .NET, należy pamiętać iż w zależności od typu pola, który został zadeklarowany w SQL zostanie on zmapowany na odpowiednik w .NET. Niektóre typy rodzą nieścisłości jak np. typ INT i INTEGER. Wydawałoby się iż oba te typy są mapowane do zwykłego int-a (Int32) - jednak nie jest tak.

W przypadku korzystania z oficjalnego konektora do bazy System.Data.SQLite (http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki) całą listę mapowania typów można znaleźć w klasie SQLiteConvert.

Dostępna tam lista przedstawia się na obecny czas następująco:

Code:
("COUNTER", DbType.Int64)
("AUTOINCREMENT", DbType.Int64)
("IDENTITY", DbType.Int64)
("LONGTEXT", DbType.String)
("LONGCHAR", DbType.String)
("LONGVARCHAR", DbType.String)
("LONG", DbType.Int64)
("TINYINT", DbType.Byte)
("INTEGER", DbType.Int64)
("INT", DbType.Int32)
("VARCHAR", DbType.String)
("NVARCHAR", DbType.String)
("CHAR", DbType.String)
("NCHAR", DbType.String)
("TEXT", DbType.String)
("NTEXT", DbType.String)
("STRING", DbType.String)
("DOUBLE", DbType.Double)
("FLOAT", DbType.Double)
("REAL", DbType.Double)
("BIT", DbType.Boolean)
("YESNO", DbType.Boolean)
("LOGICAL", DbType.Boolean)
("BOOL", DbType.Boolean)
("BOOLEAN", DbType.Boolean)
("NUMERIC", DbType.Decimal)
("DECIMAL", DbType.Decimal)
("MONEY", DbType.Decimal)
("CURRENCY", DbType.Decimal)
("TIME", DbType.DateTime)
("DATE", DbType.DateTime)
("DATETIME", DbType.DateTime)
("SMALLDATE", DbType.DateTime)
("TIMESTAMP", DbType.DateTime)
("BLOB", DbType.Binary)
("BINARY", DbType.Binary)
("VARBINARY", DbType.Binary)
("IMAGE", DbType.Binary)
("GENERAL", DbType.Binary)
("OLEOBJECT", DbType.Binary)
("GUID", DbType.Guid)
("UNIQUEIDENTIFIER", DbType.Guid)
("MEMO", DbType.String)
("NOTE", DbType.String)
("SMALLINT", DbType.Int16)
("BIGINT", DbType.Int64)

W przypadku korzystania ze zwykłego ADO.NET-a (bez ORMa) znajomość tej listy może ograniczyć ilość rzucanych wyjątków błędnego rzutowania.

Mapowania dla innych baz należy szukać albo w dokumentacji prowidera, albo w dokumentacji (dla MS SQL, Oracle i ODBC mapowiania można znaleźć np tutaj: http://msdn.microsoft.com/en-us/library)/4e5xt97a%28v=vs.110%29.aspx

środa, 15 sierpnia 2012

Pobieranie nazwy właściwości klasy

Za pomocą wyrażeń Lambda Expression można uprościć pobieranie nazwy właściwości w klasie.
Kawałek kodu który może się przydać:


Code:
        public static string GetPropertyName<T>(Expression<Func<T, object>> expression)
        {
            return expression.Body as MemberExpression != null
                ? ((MemberExpression) expression.Body).Member.Name
                : ((MemberExpression) ((UnaryExpression) expression.Body).Operand).Member.Name;
        }

Użycie:

Code:
class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(GetPropertyName<Person>(person => person.FirstName));
            Console.WriteLine(GetPropertyName<Person>(person => person.LastName));
            Console.WriteLine(GetPropertyName<Person>(person => person.Age));
        }

        public static string GetPropertyName<T>(Expression<Func<T, object>> expression)
        {
            return expression.Body as MemberExpression != null
                ? ((MemberExpression) expression.Body).Member.Name
                : ((MemberExpression) ((UnaryExpression) expression.Body).Operand).Member.Name;
        }
    }

    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }

poniedziałek, 13 sierpnia 2012

iTextSharp polskie czcionki

Biblioteka do tworzenia Pdf-ów iTextSharp w swojej podstawowej wersji tworzy Pdf-y bez polskich znaków dialektycznych.

Kod tworzący prosty pdf:


Code:
            var pdf = new Document();
            var output = new FileStream("Plik.pdf", FileMode.Create);
            var pdfWriter = PdfWriter.GetInstance(pdf, output);
            pdf.Open();
            var headerParagraph = new Paragraph("Raport śąóżćń");
            pdf.Add(headerParagraph);
            pdf.Close();
            System.Diagnostics.Process.Start("Plik.pdf");

wygeneruje następującego pdf-a:


Jak widać brakuje tutaj części polskich liter.
Aby użyć polskie litery, należy wskazać czcionkę która ma polskie litery. Możemy zrobić to w ten sposób:


Code:
            var pdf = new Document();
            var output = new FileStream("Plik.pdf", FileMode.Create);
            var pdfWriter = PdfWriter.GetInstance(pdf, output);
            pdf.Open();
            var headerParagraph = new Paragraph("Raport śąóżćń", new Font(BaseFont.CreateFont(@"C:\Windows\Fonts\Arial.ttf", BaseFont.CP1250, true)));
            pdf.Add(headerParagraph);
            pdf.Close();

Na wyjściu otrzymamy dokument z polskimi znakami dialektycznymi:


Innym sposobem jest zarejestrowanie folderu gdzie znajdują się nasze czcionki w FontFactory a następnie pobieranie ich przy pomocy metody GetFont:

Code:
            FontFactory.Register(@"C:\Windows\Fonts");
            FontFactory.GetFont("Arial");

Drugi sposób wydaje mi się bardziej wygodny i użyteczny, z drugiej strony jeżeli czcionki są porozrzucane pomiędzy różne katalogi - sposób pierwszy wydaje się bardziej dogodny.

środa, 8 sierpnia 2012

Indeks kolumny w GridView

Chcąc pobrać indeks kolumny w GridView (ASP.NET WebForms) możemy na trafić na problem, iż w GridView nie zaimplementowano takiej możliwości bezpośrednio.

Jeżeli korzystamy z kolumn, które są bindowane do pól obiektów, możemy posłużyć się właściwością DataField dla kolumny.
Problemem jest to, iż kolumny są typu DataControlField a typ ten nie zawiera właściwości DataField. Klasy dziedziczące po tym typie zawierają bądź też nie zawierają tej właściwości.
W tym przypadku możemy się posłużyć rzutowaniem, bądź też skorzystać z refleksji w celu zmniejszenia ilości warunków:

Code:
        <asp:GridView runat="server" DataSourceID="dsProducts" AutoGenerateColumns="False"
        ID="gvProducts">
            <Columns>
                <asp:BoundField DataField="ProductId" HeaderText="Id"/>
                <asp:BoundField DataField="Name" HeaderText="Nazwa"/>
                <asp:BoundField DataField="Size" HeaderText="Rozmiar"/>
                <asp:DataBoundFieldEx DataField="Weight" HeaderText="Waga" UniqeName="column" />
            </Columns>
        </asp:GridView>

Oraz metoda która pozwala wyciągnąć indeks kolumny po nazwie DataField:

Code:
using System;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public static class DataGridExtensions
    {
         public static int GetColumnIndexByName(this GridView gridView, string columnName)
         {
             gridView.Columns[]
             if (string.IsNullOrWhiteSpace(columnName))
             {
                 throw new ArgumentNullException("ColumnName can't be null");
             }

             for(int i = 0; i < gridView.Columns.Count; ++i)
             {
                 var dataFieldProperty = gridView.Columns[i].GetType().GetProperty("DataField");
                 if (dataFieldProperty != null)
                 {
                     var column = dataFieldProperty.GetValue(gridView.Columns[i], null).ToString();
                     if (!string.IsNullOrWhiteSpace(column) && column.Equals(columnName))
                     {
                         return i;
                     }
                 }
             }

             return -1;
         }
    }
}

Użycie:

Code:
var columnIndex = gvProducts.GetColumnIndexByName("Name");

niedziela, 5 sierpnia 2012

Oracle Kursory

Kursor w kontekście bazy danych można porównać o pętli, która iteruje po wierszach zwróconych przez zapytanie.

W bazie posiadam tabelę która zawiera dane o klientach:


Deklaracja ogólna kursora:

CURSOR nazwa [(parametry)] [RETURNS] IS selekt;

Przykład dla naszego kursora:

DECLARE
CURSOR myCursor IS
SELECT Imie, Nazwisko FROM klienci;

Po stworzeniu kursora możemy z niego pobrać dane na dwa sposoby:
- Instrukcja Fetch:
set serveroutput on format wraped;
DECLARE
v_pobrany_klient Klienci%ROWTYPE;
CURSOR myCursor IS
SELECT * FROM klienci;
BEGIN
dbms_output.enable;
OPEN myCursor;
LOOP
FETCH myCursor INTO v_pobrany_klient;
dbms_output.put_line(v_pobrany_klient.Imie ||' '|| v_pobrany_klient.Nazwisko);
EXIT WHEN myCursor%NOTFOUND;
END LOOP;
CLOSE myCursor;
END;

- pętla FOR:
set serveroutput on format wraped;
DECLARE
CURSOR myCursor IS
SELECT Imie, Nazwisko FROM klienci;
BEGIN
dbms_output.enable;
FOR row IN myCursor LOOP
  dbms_output.put_line(row.Imie ||' '|| row.Nazwisko);
END LOOP;
END;

Pętla ma tę przewagę nad instrukcją FETCH, że nie trzeba jawnie otwierać i zamykać kursora - prostsze użycie.

środa, 1 sierpnia 2012

MSDTC - Microsoft Distributed Transaction Coordinator

Wielu programistów nie zdaje sobie sprawy z istnienia MSDTC. Czym jest i czy warto o nim wiedzieć podczas tworzenia zapytań? W tym poście postaram się to rozjaśnić.

Jak sama nazwa mówi, MSDTC jest usługą systemu Windows zapewniającą infrastrukturę dla systemów rozproszonych transakcji. Jak wiadomo transakcja ma 4 podstawowe właściwości pochodzące od akronimu ACID:
  • Atomic - atomowość - czyli transakcja wykona się albo w całości albo w ogóle
  • Consistency - spójność - po wykonaniu transakcji nie może dojść do naruszenia jakichkolwiek więzów spójności
  • Isolation - izolacja - w przypadku gdy dwie transakcje wykonują się równocześnie w zależności od poziomu izolacji nie widzą zmian wprowadzany przez siebie nawzajem
  • Durability - trwałość - po zapisaniu transakcji system musi umożliwić uruchomienie się nawet w przypadku awarii
Główni aktorami w transakcji są:
  • Manager transakcji - MSDTC
  • Inicjator - aplikacja zapoczątkowująca transakcję
  • Manager zasobów
Przepływ jest następujący:
  1. Aplikacja inicjująca (Inicjator) wysyła żądanie do managera transakcji o udostępnienie wolnej transakcji
  2. Aplikacja kliencka wysyła żądanie do managera zasobów żądanie o wykonanie zadania jako transakcji
  3. Aplikacja kliencka zatwierdza transakcję
  4. Manager transakcji we współpracy z managerem zasobów sprawdza czy wszystkie zadania zostały wykonane poprawnie - sprawdza w ten sposób zasady ACID