11 Temmuz 2024 Perşembe

Delegate, Action, Predicate ve Func



Return type'ı ve aldığı parametre sayısı aynı  olan birden fazla metodu tek bir yerde paketlemek isteyebiliriz. Bu paketi çağırdığımız zamanda pakete eklenmiş tüm metodların eklendiği sıraya göre çağrılmalarını sağlayabiliriz. Bunu delegate ile yapabiliriz.

Delegate, Metodların referansını tutabilen bir nesnedir. Delegateleri tetiklemek için içerisinde bulunan invoke() metodu çağırılır. Eğerki delegatenin referensını tuttuğu metodlar parametre alıyorsa bu parametreler Invoke() metodu içerisine eklenmelidir. 

1-) Return tipi Void olan ve parametre almayan metodların referansını tutan delegate örneği.


2-) Return tipi Void olan parametre alan metodların referansını tutan delegate örneği.


3-) Return tipi int olan ve parametre alan metodların referansını tutan delegate örneği.

Yukarıdaki örnekte void olmayan metodlarda birden fazla metod çalıştırıldığında geriye en son hangi metod çalıştırıldıysa onun sonucu döner. Yani result değişkeninin sonucu Cikart işleminin sonucu olan 3 tür.


Action

Geriye değer döndürmeyen parametreli veya parametresiz metodları encapsule eder.



Predicate

Geriye bool değer döndüren ve kesinlikle en az bir tane parametre almak zorunda olan metodları encapsule eder.


Func

Geriye değer döndürmesi gerekir ve parametre alabilir. 

Örneğin, Func<int, bool> türünde bir delagete, bir int parametre alıp bool sonuç döndüren bir metodu ifade eder.





11 Haziran 2024 Salı

İlkel Koleksiyonların Serilizasyonu

 public class Person

{

    public int Id { get; set; }

    public string Name { get; set; }

    public string Gender { get; set; }

    public Gender Gender2 { get; set; }

    public bool Married { get; set; }

    public List<string>? Titles { get; set; }

}


Yukarıda bulunan list<string> title türündek verilerin databasede kolon olarak yazılabilmesi için

        modelBuilder.Entity<Person>()

            .Property(p => p.Titles)

            .HasConversion(

            //INSERT - UPDATE

            t => JsonSerializer.Serialize(t, (JsonSerializerOptions)null)

            ,

            //SELECT

            t => JsonSerializer.Deserialize<List<string>>(t, (JsonSerializerOptions)null)

            );

10 Haziran 2024 Pazartesi

Data Concurrency

 Data Concurrency Nedir?

Geliştirdiğimiz uygulamalarda ister istemez verisel olarak tutarsızlıklar meydana gelebilmektedir. Örneğin; birden fazla uygulamanın yahut client'ın aynı veritabanı üzerinde eşzamanı olarak çalıltığı durumlarda verisel anlamda uyuglamadan uygulamaya yahut client'tan clienta tutarsızlıklar meydana gelebilir.

Data Concurrency kavramı, uygulamalardaki veri tutarsızlığı durumlarına karşılık yönetilebilirliği sağlayacak olan davranışları kapsayan bir kavramdır.

Bir uygulamada veri tutarsızlığının olması demek o uygulamayı kullanan kullanıcıları yanıltmak demektir.

Veri tutarsızlığının olduğu uygulamalarda istatistiksel olarak yanlış sonuçlar elde edilebilir...

Stale & Dirty (Bayat & Kirli) Data Nedir?

Stale Data : Veri tutarsızlığına sebebiyet verebilecek güncellenmemiş yahut zamanı geçmiş olan verileri ifade etmektedir. Örneğin; bir ürünün stok durumu sıfırlandığı halde arayüz üzerinde bunu ifade eden bir güncelleme durumu söz konusu değilse işte bu stale data durumuna bir örnektir.


Dirty Data : Veri tutarszılığına sebebiyet verebilecek verinin hatalı yahut yanlış olduğunu ifade etmektedir. Örneğin; adı 'Ahmet' olan bir kullanıcının veritabanında 'Mehmet' olarak tutulması dirty data örneklendirmesidir.

Last In Wins (Son Gelen Kazanır) : Bir veri yapısında son yapılan aksiyona göre en güncel verinin en üstte bulunmasını/varlığını korumasını ifade eden bir deyimsel terimdir.

Pessimistic Lock (Kötümser Kilitleme)

Bir transaction sürecinde elde edilen veriler üzerinde farklı sorgularla değişiklik yapılmasını engellemek için ilgil iverilerin kitlenmesini(locking) sağlayarak değişikliğe karşı direnç oluşturulmasını ifade eden bir yöntemdir.

Bu verilerin kilitlenmesi durumu ilgili transaction'ın commit ya da rollback edilmesi ile sınırlıdır.

Deadlock( Kilitleme Çıkmazı - Ölüm Kilitlenmesi) Nedir?

Kitlenmiş olan bir verinin veirtabanı seviyesinde meydana gelen sistemsel bir hatadan dolayı kilidinin çözülememesi yahut döngüsel olarak kilitlenme durumunun meydana gelmesini ifade eden bir terimdir.

Pessimistic Lock yönteminde deadlock durumunu yaşamanız bir ihtimaldir. O yüzden değerlendirlmesi gereken ve iyi düşünülerek tercih edilmesi gerken bir yaklaşımdır pessimistic lock yaklaşımı.

WITH (XLOCK)

//using var transaction = await context.Database.BeginTransactionAsync();

//var data = await context.Persons.FromSql($"SELECT * FROM Persons WITH (XLOCK) WHERE PersonID = 5")

//    .ToListAsync();

//Console.WriteLine();

//await transaction.CommitAsync();

Optimistic Lock (İyimser Kilitmele)

Bir verinin stale olup olmadığını anlamak için herhangi bir locking işlemi olmaksızın versiyon mantığıonda çalışmamızı sağlayan yaklaşımdır.

Optimistic lock yönteminde, Pessimistic lock'da olduğu gibi veriler üzerinde tutarsızlığa mahal olabilecek değişiklikler fiziksel olarka engellenmemektedir. Yani veriler tutarsızlığı sağlayacak şekilde değiştirilebilir. 

Amma velakin Optimistic lock yaklaşımı ile bu veriler üzerindeki tutarsızlık durumunu takip edebilmek için versiyon bilgisini kullanıyoruz. Bunu da şöyle kullanıyoruz;

Her bir veriye karşılık bir versiyon bilgisi üretiliyor. Bu bilgi ister metinsel istersekte sayısal olabilir. Bu versiyon bilgisi veri üzerinde yapılan her bir değişiklik neticesinde güncellenecektir. Dolayısıyla bu güncellemeyi daha kolay bir şekild egerçkeleştirebilmek için sayısal olmasını tercih ederiz. 

EF Core üzerinden verileri sorgularken ilgili verilerin versiyon bilgilerini de in-memory'e alıyoruz. Ardından veri üzerinde bir değişiklik yapılırsa eğer bu  inmemory'deki versiyon bilgisi ile verityabanındaki versiyon bilgisini karşılaştıroyruz. Eğer ki bu karşılaştırma doğrulanıyorsa yapılan aksiyon geçerli olacaktır, yok eğer doğrulanmıyorsa demek ki verinin değeri değişmiş anlamına gelecek yani bir tutarsızlık durumu olduğu anlaşılacaktır. İşte bu durumda bir hata fırlatılacak ve aksiyon gerçekleştirilmeyecektir.

EF Core Optimistic lock yaklaşımı için genetinde yapısal bir özellik barındırmaktadır.

 1-) Property Based Configuration (ConcurrencyCheck Attribute)

Verisel tutarlılığın kontrol edilmek istendiği proeprtyler IsConcurrencyToken ile işaretlenir. Bu işaretleme neticesinde her bir entity'nin instance'ı için in-memory'de bir token değeri üretilecektir. Üretilen bu token değeri alınan aksiyon süreçlerinde EF Core tarafından doğrulacnacak ve eğer ki herhangi bir değişiklik yoksa aksiyon başarıyla sonlandırılmış olacaktır. Yok eğer transaction sürecinde ilgili veri üzerinde(ConcurrencyCheck attribute ile işaretlenmiş propertylerde) herhangi  bir değişiklik durumu söz konusuysa o taktirde üretilen token'da değiştirilecek ve haliyle doğrulama sürecinde geçerli olmayacağı anlaşılacağı için veri tutarsızlığı durumu olduğu anlaşılacak ve hata fırlatılacaktır.

public class Person

{

    public int PersonId { get; set; }

    public string Name { get; set; }

}

modelBuilder.Entity<Person>().Property(p => p.Name).IsConcurrencyToken();


//var person = await context.Persons.FindAsync(3);

//context.Entry(person).State = EntityState.Modified;

//await context.SaveChangesAsync();


2-) RowVersion Column

Bu yaklaşımda ise veritabanındaki her bir satıra karşılık versiyon bilgisi fiziksel olarka oluşturulmaktadır.

public class Person

{

    public int PersonId { get; set; }

    public string Name { get; set; }

    public byte[] RowVersion { get; set; }

}

 modelBuilder.Entity<Person>().Property(p => p.RowVersion).IsRowVersion();

//var person = await context.Persons.FindAsync(3);

//context.Entry(person).State = EntityState.Modified;

//await context.SaveChangesAsync();


IsRowVersion daha spesifik olarak bir satır için sürüm numarası tutmak için kullanılırken, IsConcurrencyToken genel olarak eşzamanlılık denetimi için herhangi bir kolonu işaretlemek için kullanılabilir


https://github.com/gncyyldz/EF-Core-Training/blob/master/Data_Concurrency/Program.cs

27 Ocak 2024 Cumartesi

HTTP Status Code

HTTP 200 OK: if you want send some additional data in the Response body. Usually used for GET request

HTTP 201 Created The request has been fulfillled, a new entity has been created. Response might contain location header pointing to the entity. So insted of returning actual  entity usually a 201 response includes a pointer to the location of the entity.  Usualyy used for POST request and sometime for PUT request. 



HTTP 202 Accepted the request has been accepted and is pending processing. So if I send the server a large cunk  of entities to process, and the process might take time. No notification is given when processing is complete. Usually used for POST an PUT request. Since these requests are a request for processing data and the client usually does not have to wait until these actions are complete

HTTP 204 No Content: The server successfully processed the request, but is not returning any content. So response should not include body

HTTP 400 Bad Request request parameters can't be validated. Problem Details.



HTTP 401 UnAuthorized 

HTTP 404 NotFound the source we were looking for is Not Found. We are going to use it when a specific entity was looked for, not with query parameter. When we are looking for a specific entity using the ID Paremeter and this entity is not found we should response 404. in contrast, when a request is made with query parameters and nothing is returned. we can return 200. Because There is no entity that  match the parameters and this is accetable.


GET             /users                    200         [John, Peter]
GET             /users/john               200         John
GET             /unknown-url-egaer        404         Not Found
GET             /users/kyle               404         User Not found
GET             /users?name=kyle`         200         []
DELETE          /users/john               204         No Content

Get metodları için;

 Eğer GetAll sorgusu yapıyorsak resource olsada olmasada geriye  200-Ok döner

        api/v1/Magazines
        [HttpGet]
        public IActionResult GetMagazines()
        {
            return Ok(DumyData.GetMagazines());
        }

 Eğer ID parameter ile sorgu yapıyorsak ID Parametresine karşılık bir resource yoksa NotFound       döner. ID Parametresine karşılık resource varsa 200-OK döner. 

        api/v1/Magazines/1
        [HttpGet("{id}")]
        public IActionResult GetMagazineById(int id)
        {
            var magazine = DumyData.GetMagazineById(id);

            if (magazine == null)
            {
                return NotFound();
            }

            return Ok(magazine);
        }
         

 Eğer Query string ile sorgu yapıyorsak filtremize karşılık bir resource olsada olmada geriye 200-Ok döneriz.

        GET api/v1/Magazines/2/articles/filter?page=100

        [HttpGet("{magazineId}/articles/filter")]
        public IActionResult GetAllArticlesByMagazineIdAndFilter(int magazineId, [FromQuery] int page)
        {
            var magazine = DumyData.GetMagazineById(magazineId);

            if (magazine is null)
            {
                return NotFound();
            }

            var data = DumyData.GetArticleByMagazineId(magazineId).FindAll(x => x.Page == page);

            return Ok(data);
        }


Post metodları için;

Post işlemi sonucu Status Code olarak 201 created dönmemiz gerekiyor. Bununla birlikte ilgili resource bilgilerini dönmemiz gerekiyor ve son olarak Response Header Location Field ile post edilen resource için URI bilgisini dönmemiz gerekiyor. 

        // api/v1/Magazines/2/articles
        [HttpPost("{magazineId}/articles")]
        public IActionResult AddArticle(int magazineId, [FromBody]ArticleCreateDTO articleDto)
        {
            var magazine = DumyData.GetMagazineById(magazineId);

            if(magazine is null)
            {
                return NoContent();
            }

            var article = DumyData.AddArticle(magazineId, articleDto);

            return CreatedAtAction("GetArticleByMagazineIdAndArticleId", new { magazineId = magazineId, id = article.Id }, article);
          }


        // api/v1/Magazines/2/articles/5
        [HttpGet("{magazineId}/articles/{id}")]
        public IActionResult GetArticleByMagazineIdAndArticleId( int magazineId, int id)
        {
            var article = DumyData.GetArticleById(id);

            if (article is null)
            {
                return NotFound();
            }

            return Ok(article);
        }


Put metodları için;

Put Http metodu resource'a yeni bir item eklemek veya var olan resource'u update etmek için kullanılır. Eğer yeni bir item eklenirse Post methodu gibi davranır. ve  201 created  dönmeliyiz. Eğer var olan bir itemi günceliyorsa 204 No Content status kodu ile dönüş yapmalıdır.


        // api/v1/Magazines/1/articles/8
        [HttpPut("{magazineId}/articles/{id}")]
        public IActionResult UpdateArticle(int magazineId, int id, [FromBody]ArticleUpdateDTO articleDto)
        {
            var magazine = DumyData.GetMagazineById(magazineId);

            if(magazine is null)
            {
                return NotFound();
            }

            var article = DumyData.GetArticleById(magazineId, id);

            if(article is null)
            {
                article = DumyData.AddArticle(magazineId, new ArticleCreateDTO() { Author = articleDto.Author, Name = articleDto.Name, Page = articleDto.Page});

                return CreatedAtAction("GetArticleByMagazineIdAndArticleId", new { magazineId = magazineId, id = article.Id }, article);
} DumyData.UpdateArticle(magazineId, id, articleDto); return NoContent(); }


Delete metodları için;

Eğer silinmek istenen resource yok ise 404 Not Found döneriz.Silme işlemi başarılı gerçekleşirse 204 No Content dönmeliyiz.

        api/v1/Magazines/1/articles/2

        [HttpDelete("{magazineId}/articles/{id}")]
        public IActionResult DeleteArticle(int magazineId, int id)
        {

            var magazine = DumyData.GetMagazineById(magazineId);

            if (magazine is null)
            {
                return NotFound();
            }

            var item = DumyData.GetArticleById(magazineId, id);

            if (item is null)
            {
                return NotFound();
            }

            DumyData.DeleteArticle(magazineId, id);

            return NoContent();
        }


.