Saturday, November 11, 2017

FluentGenerator kullanarak Oracle Entity Framework 6.x sınıflarının oluşturulması - Generating Oracle Entity Framework classes with FluentGenerator

FluentGenerator (FG) Entity Framework 6.x (EF) code first örüntüsüne göre sınıfların oluşturulması için yazılmış bir masaüstü uygulamasıdır. Oluşturulan sınıflar "fluent" mimariye göre oluşturulur ve POCO ve bağlantı (mapping) sınıfları ayrı ayrı oluşturulur.

FG, ProjectBase (PB) kütüphanesini kullandığı için uygulamanın çalıştırılması için PB' nin eklenmesi ve provider ayarlamalarının yapılması gerekir. Eğer Oracle unmanaged provider kullanılıyorsa "Oracle Client" kurulmalı ve ilgili ayarlamalar yapılmalıdır.

FG ve PB'yi aşağıdaki adresten indirebilirsiniz:

https://github.com/vyigity

Test veri tabanı olarak Oracle 11g express edition ve HR şeması içinde yer alan ögeler kullanılacaktır.



FG çalıştırıldığında config ayarlamalarına göre bağlantı cümleciği arayüzde görünecektir. Cümlecik değiştirilmek istenirse istenen yeni cümlecik girilir ve "CHANGE" tuşu ile yeni cümlecik geçerli hale getirilir. Namespace ismini kendi projenize göre belirledikten sonra "DIR" tuşu ile EF sınıflarının hangi klasör içinde oluşturulacağı seçilmelidir. Capitalization kısmında sınıf isimlerinin nasıl formatlanacağı seçilebilmektedir. Bu örnekte "Pascal" kullanılacaktır. Üstte yer alan TABLE_NAME kısmında tablo ismine göre, alttaki VIEW_NAME kısmından view ismine göre arama yapılabilir.

Örnek olarak görselde de görüleceği üzere "Employees" tablosuna ilişkin sınıfları oluşturmak istiyoruz. Arama kısmına "EMPL" yazarak istediğimiz tabloya ulaştık ve yön tuşları ile tabloyu sağ tarafta yer alan grid içine alarak bu tablonun oluşturulacağını belirttik. Son olarak "GENERATE" tuşu nu kullandığımızda önceden seçtiğimiz klasör içinde sınıflar aşağıdaki gibi oluşturulacaktır:

.\Generate\Context.cs

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using YourNameSpace.Models.Mapping;

namespace YourNameSpace.Models
{
    public partial class DatabaseContext : DbContext
    {
        static DatabaseContext()
        {
            Database.SetInitializer<DatabaseContext>(null);
        }

        public DatabaseContext()
            : base("Name=Context")
        {
        }

        public DbSet<Employees> Employeess { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new EmployeesMap());
        }
    }
}

Context sınıfı EF'nin temel sınıfıdır ve FG foreign key (FK) ilişkileri oluşturmadığı için bu konuyla ilgili kodlar elden bu sınıf içine eklenmelidir. Map sınıfları "OnModelCreating" fonksiyonu içine yukarıdaki gibi eklenmeli ve DbSet tanımlaması sonraki eklentiler için elden yapılmalıdır.

.\Generate\Employees.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace YourNameSpace.Models
{
    public partial class Employees
    {
        public int EmployeeId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public string PhoneNumber { get; set; }
        public DateTime HireDate { get; set; }
        public string JobId { get; set; }
        public Nullable<decimal> Salary { get; set; }
        public Nullable<decimal> CommissionPct { get; set; }
        public Nullable<int> ManagerId { get; set; }
        public Nullable<short> DepartmentId { get; set; }

    }
}

Yukarıda EF Employees POCO sınıfının nasıl göründüğü verilmiştir.

.\Generate\Mapping\EmployeesMap.cs

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

namespace YourNameSpace.Models.Mapping
{
    public class EmployeesMap : EntityTypeConfiguration<Employees>
    {
        public EmployeesMap()
        {
            // Primary Key
            this.HasKey(t => new { t.EmployeeId });

            // Properties
            this.Property(t => t.EmployeeId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

            this.Property(t => t.FirstName)
                .HasMaxLength(20);

            this.Property(t => t.LastName)
                .IsRequired()
                .HasMaxLength(25);

            this.Property(t => t.Email)
                .IsRequired()
                .HasMaxLength(25);

            this.Property(t => t.PhoneNumber)
                .HasMaxLength(20);

            this.Property(t => t.JobId)
                .IsRequired()
                .HasMaxLength(10);

            // Table & Column Mappings
            this.ToTable("EMPLOYEES", "HR");
            this.Property(t => t.EmployeeId).HasColumnName("EMPLOYEE_ID");
            this.Property(t => t.FirstName).HasColumnName("FIRST_NAME");
            this.Property(t => t.LastName).HasColumnName("LAST_NAME");
            this.Property(t => t.Email).HasColumnName("EMAIL");
            this.Property(t => t.PhoneNumber).HasColumnName("PHONE_NUMBER");
            this.Property(t => t.HireDate).HasColumnName("HIRE_DATE");
            this.Property(t => t.JobId).HasColumnName("JOB_ID");
            this.Property(t => t.Salary).HasColumnName("SALARY");
            this.Property(t => t.CommissionPct).HasColumnName("COMMISSION_PCT");
            this.Property(t => t.ManagerId).HasColumnName("MANAGER_ID");
            this.Property(t => t.DepartmentId).HasColumnName("DEPARTMENT_ID");
        }
    }
}

EmployeesMap sınıfı EF haritalama ve bazı validation kodlarını içeren sınıftır. Validation kodlarının burada bulunması zorunlu değildir. İstenmesi durumunda etiket (Attribute) usulü de uygulanabilir. Bütün sınıfları projenize eklediğinizde EF ile ilgili veri tabanı nesneleri üzerinde işlem yapmaya başlayabilirsiniz.

Monday, October 16, 2017

ProjectBase ile DataTable Yerine Önceden Tanımlı Nesne Kullanarak Veri Çekme (Tip Belirtimli - Typed)

Daha önceki yazılarda DataTable üzerinde veri çekme örneği yapmıştık. DataTable ile yapılan işlemler "Typed" yani belirli türlü olmadığı için kodlamayı zorlaştırmaktadır. Şimdi kendi oluşturduğumuz bir sınıfa ait nesneyi verileri tutmak için kullanacağız. Yine "EMPLOYEES" tablosunu kullanalım ve önce sınıfı aşağıdaki gibi oluşturalım:

public class EMPLOYEE
{
    public string FIRST_NAME { get; set; }
    public string LAST_NAME { get; set; }
    public decimal SALARY { get; set; }
    public DateTime? HIRE_DATE { get; set; }

}

Burada dikkat edilmesi gereken husus yazacağımız sorgudan gelecek olan sütun isimlerinin "Property" isimleri ile eşleşmesidir. Eşleme büyük-küçük harfe duyarlı değildir. Şimdi bu sınıfı kullanacak veri çekme kodlarını yazalım:

var db = DatabaseFactory.GetDbObject();
var gen = QueryGeneratorFactory.GetDbObject();

gen.SelectText = "select * from employees where employee_id < 112";

List<EMPLOYEE> employees = db.GetObjectList<EMPLOYEE>(gen.GetSelectCommandBasic());

Yukarıdaki kod çalıştırıldığında id numarası 112'den küçük kayıtları yazdığımız sınıfın bir listesi olarak elde edeceğiz.

"Bu yazıda "Oracle Managed Provider", Oracle 11g Express Edition ve HR şeması test verileri kullanılmıştır."

"https://github.com/vyigity/ProjectBase"

Sunday, October 15, 2017

ProjectBase Data Access and Utility Library - ProjectBase Veri Erişim ve Yazılım Destek Kütüphanesi

ProjectBase (PB) is a Utility and Data Access library. PB designed with a database independent interface oriented approach to ensure extentibility and reliablity. PB's codes can be changed or manipulated easily. PB can be installed with nuget package manager console:
PM> Install-Package vyigity.ProjectBase -Version 4.0.0

PB has 3 type of data access:
  • Automatic Connection Management: Using single connection object and while executing a command, connection is opened and closed automatically.
  • Manuel Connection Management: Using single connection object and connection is opened and closed by developer manually.
  • Transaction Mode: PB supports PL/SQL type code writing of transactional processes. PB creates transactions and manages them automatically.
PB currently supports Oracle (Managed-Unmanaged Provider), SQL Server databases and OleDb. PB supports MySql provider with v2.0.0 and PostgreSQL provider with v3.0.0.
Also PB supports low level object mapping features.

Project Adress:
For introduction:
For connection management examples:
For transactions examples:
For DML examples:
For parametric database procedures and functions examples:

ProjectBase ve QueryGenerator ile Veri Tabanı Prosedür İşlemleri

QueryGenerator ile veri tabanı prosedür veya fonksiyonlarına erişmek için öncelikle örnek veri tabanı fonksiyonlarını oluşturalım:

FUNCTION "GETUSERNAME" (
  "PARAM1" IN NUMBER) RETURN varchar2 IS

  RETURN_VAL varchar2(150);

BEGIN 

  select FIRST_NAME ||' ' || LAST_NAME into RETURN_VAL from employees where employee_id = PARAM1;
  
  RETURN RETURN_VAL;

END;


FUNCTION "GETSALARY" (
  "PARAM1" IN NUMBER) RETURN number IS

  RETURN_VAL NUMBER;

BEGIN 
  
  select SALARY into RETURN_VAL from employees where employee_id = PARAM1;

  RETURN RETURN_VAL;

END;

Yukarıda string değer döndüren "GETUSERNAME" ve decimal değer döndüren "GETSALARY" fonksiyonlarını oluşturduk. Aşağıda gibi bu fonksiyonları .NET projemiz içinde kullanabiliriz:

var db = DatabaseFactory.GetDbObject();
var gen = QueryGeneratorFactory.GetDbObject();

gen.ProcedureName = "GETSALARY";
gen.AddDataParameter("RETURN_VAL", DbType.Decimal, null, 150, System.Data.ParameterDirection.ReturnValue);
gen.AddDataParameter("PARAM1", 100);

db.ExecuteQuery(gen.GetProcedure());

var return_val = gen.GetParameterValue("RETURN_VAL");

string gen2 = QueryGeneratorFactory.GetDbObject();

gen2.ProcedureName = "GETUSERNAME";
gen2.AddDataParameter("RETURN_VAL", DbType.String, null, 150, System.Data.ParameterDirection.ReturnValue);
gen2.AddDataParameter("PARAM1", 100);

db.ExecuteQuery(gen2.GetProcedure());

decimal return_val2 = gen2.GetParameterValue("RETURN_VAL");

Yukarıda görüldüğü üzere QueryGenerator ile standart bir kod arayüzü ile fonksiyon ve prosedür erişimleri yapılabilmektedir.

"Bu yazıda "Oracle Managed Provider", Oracle 11g Express Edition ve HR şeması test verileri kullanılmıştır."

"https://github.com/vyigity/ProjectBase"

Saturday, October 14, 2017

ProjectBase ile QueryGenerator kullanarak parametrik DML işlemleri

"QueryGenerator" (QG) standart olarak parametrik veri tabanı işlemlerini gerçekleştirilmesi sağlayan sınıftır. Parametrik işlemler SQL injection gibi güvenlik açıklarına karşı kesinlikle tercih edilmesi gereken bir yöntemdir. Parametrik işlemlerde kullanılan ve sql texti içinde yer alan bir sözün parametre olup olmadığının anlaşılmasını sağlayan ve verita banına göre değişebilen bazı karakterler vardır. Bunlar SQL Server veri tabanı için "@", Oracle veri tabanı için ":" karakterleridir. Örneğin SQL Server içi parametre yazılacaksa "@Param" şeklinde, Oracle için yazılacaksa ":Param" şeklinde yazılır. QG sınıfı standart olarak ":Param" şeklinde yazılacak şekilde hazırlanmıştır.

Aşağıdaki kod bloku ile QG ile nasıl veri çekilebileceği gösterilmiştir:

var gen = QueryGeneratorFactory.GetDbObject();
var db = DatabaseFactory.GetDbObject();
string sql = "select * from employees where employee_id = :ID";

gen.SelectText = sql;
gen.AddFilterParameter("ID", 100);

var dt = db.ExecuteQueryDataTable(gen.GetSelectCommandBasic());

Yukarıdaki örnekte görüldüğü üzere ":ID" parametresi ile bir filterparameter oluşrulmuş ve 100 id numaralı kişinin bilgileri çekilmiştir.

QG ile Update ve Insert işlemleri de kolaylıkla yapılabilmektedir. Aşağıdaki kod bloğunda 101 id numaralı kişinin bilgileri güncellenmiştir:

var db = DatabaseFactory.GetDbObject();
var gen = QueryGeneratorFactory.GetDbObject();
gen.TableName = "EMPLOYEES";
gen.AddDataParameter("FIRST_NAME", "VELI YIGIT");
gen.AddDataParameter("LAST_NAME", "YOLCU");
gen.AddFilterParameter("Param1", 101);
gen.FilterText = "WHERE employee_id = :Param1";

db.ExecuteQuery(gen.GetUpdateCommand());

Yukarıdaki kod bloğundan anlaşıldığı üzere sadece değiştirilecek alanların parametre olarak eklenmesi yeterlidir. Gerekli update komutu QG tarafından oluşturulmaktadır. Burada dikkat edilmesi  gereken nokta filtre içinde yer alan parametreler "FilterParameter" olarak eklenmelidir.

QG ile Insert işlemi aşağıdaki gibi yapılabilmektedir:

var db = DatabaseFactory.GetDbObject();
var gen = QueryGeneratorFactory.GetDbObject();
gen.TableName = "EMPLOYEES";
gen.AddDataParameter("EMPLOYEE_ID", "300");
gen.AddDataParameter("FIRST_NAME", "VELI YIGIT");
gen.AddDataParameter("LAST_NAME", "YOLCU");
gen.AddDataParameter("EMAIL", "vyigity@deneme.com");
gen.AddDataParameter("HIRE_DATE", new DateTime(2017,10,14));
gen.AddDataParameter("JOB_ID", "SH_CLERK");

db.ExecuteQuery(gen.GetInsertCommand());

Update komutuna benzer olarak Insert komutunda da eklenecek alanların DataParameter olarak eklenmesi yeterlidir.

"Bu yazıda "Oracle Managed Provider", Oracle 11g Express Edition ve HR şeması test verileri kullanılmıştır."

"https://github.com/vyigity/ProjectBase"

Sunday, October 8, 2017

ProjectBase ile Veri Tabanı Bağlantı Türlerine Göre İşlemler

ProjectBase "TransactionMode" dışında bağlantı kontrolüne göre 2 yöntem içermektedir. "ManuelConnectionManagement" ile veri tabanı işlemleri şöyle yapılabilmektedir:

IDatabase2 db = DatabaseFactory.GetDbObject();
db.ExecuteQuery("update employees set salary = 3000 where employee_id = 100");

//Yeni veri tabanı bağlantısı kuruldu
//salary = 3000 oldu
//Bağlantı kesildi

db.ExecuteQuery("update employees set salary = 24000 where employee_id = 100");

//Yeni veri tabanı bağlantısı kuruldu
//salary = 24000 oldu
//Bağlantı kesildi

Yukarıdaki kod örneğinde gösterildiği üzere her işlemde bağlantı kurulup kapatılmaktadır. Art arda işlemlerde bu durum performans sorunu çıkaracağından bu durumda "ManuelConnectionManagement" tercih edilmelidir. Bu durumda aynı işlem iki farklı kod biçiminde yazılabilir.

IDatabase2 db2 = DatabaseFactory.GetDbObject(DbSettings.ManuelConnectionManagement);
db2.ExecuteQuery("update employees set salary = 3000 where employee_id = 100");

//Veritabanı bağlantısı kuruldu
//salary = 3000 oldu
//Bağlantı açık bırakıldı

db2.ExecuteQuery("update employees set salary = 24000 where employee_id = 100");

//Eski bağlantısı kullanıldı
//salary = 24000 oldu
//Bağlantı açık bırakıldı

db2.CloseConnection();

//Bağlantı kesildi.

Yukarıdaki örnekte görüldüğü üzere "CloseConnection" çağrılmadan bağlantı sonlandırılmamaktadır. Aynı kod aşağıdaki biçimde de yazılabilir:

using (IDatabase2 db = DatabaseFactory.GetDbObject(DbSettings.ManuelConnectionManagement))
{
    db.ExecuteQuery("update employees set salary = 3000 where employee_id = 100");

    //Veritabanı bağlantısı kuruldu
    //salary = 3000 oldu
    //Bağlantı açık bırakıldı

    db.ExecuteQuery("update employees set salary = 24000 where employee_id = 100");

    //Eski bağlantısı kullanıldı
    //salary = 24000 oldu
    //Bağlantı açık bırakıldı           
}

//Bağlantı kesildi.

"Bu yazıda "Oracle Managed Provider", Oracle 11g Express Edition ve HR şeması test verileri kullanılmıştır."

"https://github.com/vyigity/ProjectBase"

Saturday, October 7, 2017

ProjectBase ile Veri Tabanı İşlemleri (Transaction Örneği)

"ProjectBase" kütüphanesi otomatik transaction yönetimi ve connection yönetimi yapmaktadır. Veritabanı erişim sınıfları 3 modda çalışmaktadır. Bunlar:

* AutoConnectionManagement
* ManuelConnectionManagement
* TransactionMode

Veri tabanı erişim sınıfları ön tanımlı olarak "AutoConnectionManagement" modda çalışmaktadır. Bu modda klasik olarak her işlemde bağlantı açılıp işlem sonlandığında bağlantı kapatılmaktadır. Bu yöntem sıralı işlemlerde yavaş çalıştığından "ManuelConnectionManagement" modunda bağlantının ne zaman açılıp kapanacağı yazılımcı tarafından yönetilerek performans kazanımı yapılabilmektedir. TransactionMode ise PL/SQL tipinde kod yazımı için geliştirilmiştir.

Aşağıdaki örnekte TransactionMode kullanılarak nasıl işlem yapılacağı gösterilmiştir:

using (IDatabase2 db = DatabaseFactory.GetDbObject(DbSettings.TransactionMode))
{
    //salary = 24000

    db.ExecuteQuery("update employees set salary = 3000 where employee_id = 100 ");
    db.Commit();

    //salary = 3000 oldu

    db.ExecuteQuery("update employees set salary = 5000 where employee_id = 100 ");
    db.Commit();

    //salary = 5000 oldu

    db.ExecuteQuery("update employees set salary = 6000 where employee_id = 100 ");
    db.ExecuteQuery("update employees set manager_id = 101 where employee_id = 100 ");
    db.Commit();

    //salary = 6000 ve manager 101 oldu

    db.ExecuteQuery("update employees set salary = 10000 where employee_id = 100 ");
    db.ExecuteQuery("update employees set manager_id = null where employee_id = 100 ");
    db.RollBack();

    //salary = 6000 ve manager 101 kaldı

    db.ExecuteQuery("update employees set salary = 24000 where employee_id = 100 ");
    db.ExecuteQuery("update employees set manager_id = null where employee_id = 100 ");
    db.Commit();

    //salary = 24000 ve manager null oldu

    db.ExecuteQuery("update employees set salary = 50000 where employee_id = 100 ");

    throw new Exception("Fatal Error!");

    //Son işlem geri alındı.
}

Yukarıda görüldüğü gibi veri tabanı erişim sınıfı  transaction yönetimini otomatik olarak gerçekleştirdi. Yani yukarıdaki kod incelendiğinde 6 tane transaction otomatik olarak oluşturulmuş ve işlenmiştir. Veri tabanı erişim sınıfı ön tanımlı olarak hata olması durumunda rollback yapmaktadır. Bu yüzden son işlem geri alınmıştır.

"Bu yazıda "Oracle Managed Provider", Oracle 11g Express Edition ve HR şeması test verileri kullanılmıştır."

"https://github.com/vyigity/ProjectBase"