EntityFramework ile çalışırken oldukça kullanışlı olan IQueryable arayüzünü kullanırız. IQueryable arayüzü veritabanı için query hazırlanması ve düzenlenmesini sağlar. Bahse konu arayüz için birçok uzantı (extension) metod  mevcuttur. Bunların en başında Where uzantı metodu gelir.

Alt kısımda vereceğim örnekte Where metodu ile sorgulanan kullanıcının ilişkili departmanları listelenmektedir.

public IDataResult<List<DepartmentDto>> ListByUserId(int UserId)
{
    using (var db = new MainDbContext())
    { 
        var data = db.UserDepartments.Where(p => p.UserId == UserId)
            .Select(p => p.Department)
            .ToList();

        var result = _mapper.Map<List<DepartmentDto>>(data);

        return new SuccessDataResult<List<DepartmentDto>>(result);
    }            
}

Ancak bazı durumlarda Where metodunun uygulanmasını belirli bir koşula bağlamak isteyebiliriz. Örneğimizdeki ListByUserId metodunda UserId parametresi gelirse bu UserId ile, DepartmentId parametresi gelirse DepartmentId ile sorgulama yapmak isteyelim. Bu durumda metod şu şekilde olabilir.

public IDataResult<List<DepartmentDto>> ListByUserId(int? UserId, int? DepartmentId)
{
    using (var db = new MainDbContext(null))
    {
        var query = db.UserDepartments.AsQueryable();

        if (UserId.HasValue)
            query = query.Where(p=> p.UserId == UserId.Value);
        if (DepartmentId.HasValue)
            query = query.Where(p => p.DepartmentId == DepartmentId.Value);

        var data = query.Select(p => p.Department)
            .ToList();

        var result = _mapper.Map<List<DepartmentDto>>(data);

        return new SuccessDataResult<List<DepartmentDto>>(result);
    }            
}

Metoda baktığımızda iki adet if ile koşullu bir şekilde Where metodu uygulanmaktadır. Sonrasında nihai olarak ToList() metodu çağrılarak veri elde edilmektedir. Burada iki adet durum söz konusu ancak bazı senaryolarda 10’larca koşula bağlı queryler oluşabilir. İşte bu yüzden Where metodu ile aynı işlemi yapan ancak koşula bağlı işlemi gerçekleştiren WhereIf metodunu hazırlarız. WhereIf metodu kullanıldığında  örneğimiz şu şekilde olacaktır.

public IDataResult<List<DepartmentDto>> ListByUserId(int? UserId, int? DepartmentId)
{
    using (var db = new MainDbContext(null))
    {
        var data = db.UserDepartments
            .WhereIf(UserId.HasValue, p => p.UserId == UserId.Value)
            .WhereIf(DepartmentId.HasValue, p => p.DepartmentId == DepartmentId.Value)
            .Select(p => p.Department)
            .ToList();

        var result = _mapper.Map<List<DepartmentDto>>(data);

        return new SuccessDataResult<List<DepartmentDto>>(result);
    }            
}

Görüldüğü üzere ListUserById metodu daha okunaklı ve anlaşılır hale geldi.

WhereIf extension metodunu ekleyelim,

public static class LinqExtensions
    {
        public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool IsInQuery, Expression<Func<T, bool>> predicate)
        {
            if (IsInQuery)
                query = query.Where(predicate);

            return query;
        }

        public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> query, bool IsInQuery, Func<T, bool> predicate)
        {
            if (IsInQuery)
                query = query.Where(predicate);

            return query;
        }
    }

LinqExtensions classını projenize dahil edebilir ve kullanabilirsiniz. Normal kullanımda üstteki kod örneği yeterlidir.

Eğer Repository pattern kullanıyorsanız farklı şekillerde WhereIf metoduna erişebilirsiniz. İlgili extension metodu IQueryable arayüzü altında olacağı için öncelikle arayüz çağrılmalı ve metod kullanılmalıdır. Diğer yol ise repository arayüzüne extension metodunu çağıran bir proxy metod eklemektir.

Repository metodu şu şekilde olabilir.

public IQueryable<T> Where(Expression<Func<T, bool>> where)
{
    return _objectSet.Where(where);
}

public IQueryable<T> WhereIf(bool IsInQuery, Expression<Func<T, bool>> where)
{
    return _objectSet.WhereIf(IsInQuery, where);
}

Objectset burada Repository constructor metodunda dbcontext.set<T>() metodu ile elde edilen DbSet sınıfı objesidir. Rapository ile ilgili yazıma buradan ulaşabilirsiniz.

public interface IRepository<T> where T : class
{
    IQueryable<T> Where(Expression<Func<T, bool>> where);
    IQueryable<T> WhereIf(bool IsInQuery, Expression<Func<T, bool>> where);
}
public class Repository<T> : IRepository<T> where T : class
{
    private DbSet<T> _objectSet { get; set; }
    public Repository(MainDbContext Dbcontext)
    {
        _objectSet = Dbcontext.Set<T>();
    }
}

Repository deseni kullanıldığında ilk örneğimizdeki ListUserbyId metodu şu şekilde olacaktır.

public IDataResult<List<DepartmentDto>> ListByUserId(int? UserId, int? DepartmentId)
{
    var data = userDepartmentRepo
        .WhereIf(UserId.HasValue, p => p.UserId == UserId.Value)
        .WhereIf(DepartmentId.HasValue, p => p.DepartmentId == DepartmentId.Value)
        .Select(p => p.Department)
        .ToList();

    var result = _mapper.Map<List<DepartmentDto>>(data);

    return new SuccessDataResult<List<DepartmentDto>>(result);
}

Görüldüğü üzere extension metodlar hayatımızı kolaylaştırır, yazılım geliştirme sürecinin en önemli parçası olan bakım işleminde kodun okunabilirliğini arttırmış olurlar.

Sağlıkla kalın.

Kategoriler: CSharp

0 yorum

Bir cevap yazın

Avatar placeholder

E-posta hesabınız yayımlanmayacak.

*