Skip to main content

Entity Framework – Kompleks Sorgular için Generic Önbellekleme Metodu

Geçtiğimiz günlerde gerçekleştirdiğim Veritabanı Yerine Cache’deki Verilerle Çalışmak webinerine yapılan katılımdan ve webiner sonrasında mail yoluyla takipçilerimle yaptığım konuşmalardan oldukça memnunum. Birçok kişiye yol göstermek ve birlikte güzel beyin fırtınaları yapmak oldukça keyifli oluyor. Webinerde bütün basit LINQ ifadeleri ile aldığımız sorgu sonuçlarını Entity Framework’te generic metotlarda nasıl cacheleyebileceğimizi incelemiştik. Kompleks sorgular için kullanılacak metodu da blogumda yayınlayacağımı belirtmiştim, işte ilgili kodlar aşağıda yer almakta.

Karmaşık sorgularda generic bir yapı oluşturabilmek için Cache’de tutacağımız key değerini ancak sorgunun t-sql ifadesine dönüşmüş halini kullanarak sağlıklı şekilde yapabiliriz. Bu nedenle ToTraceString() metodu aracılığıyla elimizdeki LINQ ifadesini t-sql ifadesine dönüştürmemiz ve Cache’e atılacak nesnenin key değerini t-sql ifadesi olarak kullanmamız gerekiyor. Aşağıdaki extension metot tüm LINQ sorgularında kullanılabilir.

public static class IQueryableExtension
{
    public static List<T> GetCache<T>(this IQueryable<T> query)
    {
        string sql = ((ObjectQuery)query).ToTraceString();
        if (HttpContext.Current.Cache[sql] == null)
        {
            List<T> list = query.ToList();
            HttpContext.Current.Cache.Insert(sql, list);
        }
        return HttpContext.Current.Cache[sql] as List<T>;
    }
}

 

Örnek kullanım şekilleri ise şöyle:

using (NorthwindEntities context = new NorthwindEntities())
{
    var result = context.Products.Join(context.Categories,
                                    p => p.CategoryID,
                                    c => c.CategoryID,
                                    (p, c) => new { Products = p, Categories = c }).GetCache();

    var result2 = context.Products.GetCache();

    var result3 = (from p in context.Products
                where p.CategoryID == 2
                select p).GetCache();
}

Entity Framework – Kompleks Sorgular için Generic Önbellekleme Metodu” hakkında 8 yorum

  1. Elinize sağlık sayenizde bir yol daha öğrendik. TraceString bu işin püf noktası sanırım.Yalnış anladıysam düzeltin,TraceString ile linq ifadeleri table, sorgu veya sp olsun sorgu ifadesine dönüştürüp HttpContext.Current.Cache[sql] as List; sonucu alıyoruz…

  2. Bu metodu dersinizde anlattığınız EntityCacheHelper veya cache layer da nasıl kullanabiliriz?

  3. Evet doğrudur, ancak SP kullanımında ToTraceString metodu kullanılamıyor maalesef, dolayısıyla SP sonuçlarını cachelemek için generic bir yöntem bulamadım ben testlerimi yaparken.

    Bu metodu EntityCacheHelper sanırsam yardımcı sınıftı, buradaki örnekte extension sınıfı kullandım. Yani EntityCacheHelper sınıfında “this IQueryable query” parametresindeki this ifadesi olmadan eklenip sorgu cümlelerinin sonunda tıpkı webinerde kullanılan Get metodu gibi kullanılabilir.

  4. sanırım burada bir hata var yada ben yanlış yapıyorum. ilk gönderdiğim sorgu;
    SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[ProductName] AS [ProductName],
    [Extent1].[ProductPicturePath] AS [ProductPicturePath],
    [Extent2].[Id] AS [Id1],
    [Extent2].[LKey] AS [LKey],
    [Extent2].[Comment] AS [Comment],
    [Extent1].[ProductOsTypeId] AS [ProductOsTypeId],
    [Extent1].[IsMobile] AS [IsMobile]
    FROM [dbo].[Product] AS [Extent1]
    LEFT OUTER JOIN [dbo].[LanguageKey] AS [Extent2] ON [Extent1].[LanguageKeyId] = [Extent2].[Id]
    WHERE [Extent1].[Id] = @p__linq__0

    Id== 1 olarak geçiyorum.

    ikinci sorgum da ise Id==2 olarak geçiyorum. ama yukardaki sorgu birebir httpcontexde olduğundan dolayı sorgumun sonucunda bir değişiklik olmuyor.acaba bunun önüne geçmenin bir yolu varmı. sonuçta aynı sorguyu çekiyorum ama where condition’daki id değerim 1 değil 2.

    teşekkür ederim

  5. Merhaba Emrah,

    GetCache metodunu aşağıdaki şekliyle dener misin? Eğer sağlıklı şekilde çalıştığını test edebilirsen haber verirsen çok sevinirim, kodu güncellerim ki başkaları da faydalansın 😉

    public static List GetCache(this IQueryable query)
    {
    string sql = ((ObjectQuery)query).ToTraceString();
    if (HttpContext.Current.Cache[sql] == null)
    {
    List
    list = query.ToList();
    HttpContext.Current.Cache.Insert(sql, list);
    }

    foreach (var parameter in ((ObjectQuery)query).Parameters)
    sql += parameter.Name + “=” + parameter.Value;

    return HttpContext.Current.Cache[sql] as List;
    }

  6. Merhaba umut bey;
    bu seferde
    SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[ProductName] AS [ProductName],
    [Extent1].[ProductPicturePath] AS [ProductPicturePath],
    [Extent2].[Id] AS [Id1],
    [Extent2].[LKey] AS [LKey],
    [Extent2].[Comment] AS [Comment],
    [Extent1].[ProductOsTypeId] AS [ProductOsTypeId],
    [Extent1].[IsMobile] AS [IsMobile]
    FROM [dbo].[Product] AS [Extent1]
    LEFT OUTER JOIN [dbo].[LanguageKey] AS [Extent2] ON [Extent1].[LanguageKeyId] = [Extent2].[Id]
    WHERE [Extent1].[Id] = @p__linq__0p__linq__0 =1

    şeklinde bir sorgu oluşturuyor ve buda geriye null list olarak dönüyor.

    İyi çalışmalar dilerim.

  7. Merhaba Umut Bey;
    Düzeltme yapmak istedim;
    Sorgunun son satırı şu şekilde “where kısmı”;

    WHERE [Extent1].[Id] = @p__linq__0p__linq__0 =1p__linq__0 =1

    Kodunuzu ise şu şekilde çalıştırıyorum
    public static IList GetCache(this IQueryable query)
    {
    string sql = ((ObjectQuery)query).ToTraceString();
    if (HttpContext.Current.Cache[sql] == null)
    {
    IList list = query.ToList();
    HttpContext.Current.Cache.Insert(sql, list);
    }
    sql = ((ObjectQuery) query).Parameters.Aggregate(sql,
    (current, parameter) =>
    current + (parameter.Name + ” =” + parameter.Value));
    var t = HttpContext.Current.Cache[sql] as List;
    return t;
    }

    Çağırma kısmım ise;
    private static readonly Expression<Func>
    FillExpression = p => new ProductDto
    {
    ProductId = p.Id,
    ProductName = p.ProductName,
    ProductPicturePath = p.ProductPicturePath,
    LanguageKey = p.LanguageKey,
    ProductOsTypeId = p.ProductOsType.Id,
    IsMobile = p.IsMobile,
    };
    public IList GetListProductDtoWithProductId(int productId)
    {

    return GetObjectQuery().Where(p => p.Id == productId).Select(FillExpression).GetCache();

    }

    GetObjectQuery() Entitynin adı diyebiliriz.

    Teşekkür ederim

  8. ——Altarnatif Kullanım——
    List comp;
    if (Cache[“ComplaintCache”] == null)
    {
    string query = @”select top(6) Bn.BusinessName, Bd.Picture, Com.ID from BusinessName Bn
    inner join BusinessDetail Bd on Bd.BusinessID = Bn.ID
    inner join Complain Com on Com.BusinessID = Bn.ID
    order by Com.Times desc”;

    comp = new List(entity.ExecuteStoreQuery(query).ToList());

    Cache.Insert(“ComplaintCache”, comp, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration);
    }
    else
    comp = Cache.Get(“ComplaintCache”) as List;

    public class GetItems
    {
    public int ID { get; set; }
    public string BusinessName { get; set; }
    public string Picture { get; set; }
    }

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir