3

I used Repository pattern that I saw on online tutorial...

Everything works fine except for find method, I have no idea how to work with this and I'm having hard time understanding Expressions or Func types. I used linq and lambda before but I'm begginer and still don't use it fluently...

public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
    return Context.Set<TEntity>().Where(predicate);
}

I have this model class:

public partial class Artikl
{
        [Browsable(false)]
        public int IDArtikli { get; set; }
        public string Barkod { get; set; }
        [DisplayName("Šifra")]
        public Nullable<int> Sifra { get; set; }
        public string Naziv { get; set; }
        [DisplayName("JM")]
        public string JedinicaMjere { get; set; }
        public decimal Tarifa { get; set; }
        [DisplayName("Prodajna")]
        public Nullable<decimal> ProdajnaCijena { get; set; }
        [Browsable(false)]
        public Nullable<bool> Flag { get; set; }
        public Nullable<decimal> Kalo { get; set; }
        [DisplayName("Nabavna")]
        public Nullable<decimal> NabavnaCijena { get; set; }
        [DisplayName("Veleprodajna")]
        public Nullable<decimal> VeleprodajnaCijena { get; set; }
        public Nullable<decimal> Zalihe { get; set; }
 }

My question is how can I get the Artikl item based on property "Sifra". I have no idea how to call this method...

private void txtSifra_TextChanged(object sender, EventArgs e)
{
     var artikl = _UnitOfWork.Artikl.Find(???);
     txtNaziv.Text = artikl.Naziv;
}
solujic
  • 924
  • 1
  • 18
  • 43

3 Answers3

4

Other answers already explained how to use expression but I want to mention one thing that is often overlooked when using so-called repository pattern:

public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
    return Context.Set<TEntity>().Where(predicate);
}

This returns IEnumerable<TEntity> and because of that this:

var result = _UnitOfWork.Artikl.Find(c => c.Sifra == 1).FirstOrDefault()

Will not execute whole query in database. The database query will look (roughly) like this:

select * from Artikl where Sifra = 1 -- < not efficient

and not like this:

select top 1 * from Artikl where Sifra = 1 -- < efficient

To fix this issue you have to either return IQueryable:

public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
    return Context.Set<TEntity>().Where(predicate);
}

Or make separate method for every query you are going to make:

public TEntity FindFirst(Expression<Func<TEntity, bool>> predicate)
{
    return Context.Set<TEntity>().Where(predicate).FirstOrDefault();
}
solujic
  • 924
  • 1
  • 18
  • 43
Evk
  • 98,527
  • 8
  • 141
  • 191
  • why is "select * from Artikl where Sifra = 1" not efficient? I don't understand are you trying to point out? – solujic Mar 03 '17 at 10:32
  • @ChenChi, http://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet - this is to do with greedy loading too many records from the DB into memory. – G0dsquad Mar 03 '17 at 10:33
  • 3
    @ChenChi I try to point out that "select **top 1** from Artikl where Sifra = 1" is more efficient than just "select * from Artikl where Sifra = 1". And if you return IEnumerable and later use FirstOrDefault - the latter query is executed. Worst part is that it will most likely go unnoticed, until the point where you will make a lot of queries or when your table becomes large (like at the point when you publish your code from development to production). – Evk Mar 03 '17 at 10:33
2

You need to pass a lambda expression to satisfy Expression<Func<TEntity, bool>> predicate. You can get the item based on property "Sifra" by doing this:

var artikl = _UnitOfWork.Artikl.Find(q => q.Sifra == "some int value").FirstOrDefault();

Hope it helps!

solujic
  • 924
  • 1
  • 18
  • 43
mindOfAi
  • 4,412
  • 2
  • 16
  • 27
  • 2
    Oh. Sorry, but in that case, I suggest you use FirstOrDefault(), so it won't cause some crashes. Using First() when your Find() didn't return anything would lead to a crash. – mindOfAi Mar 03 '17 at 10:14
1

The usage of Expression<Func<TEntity, bool>> is like so, just pass in a lambda expression (pseudo-code):

var result = context.set.Find(x => x.Property == value);

So in your case:

var artiklList = _UnitOfWork.Artikl.Find(x => x.Sifra == 1);
var artikl = artiklList.FirstOrDefault();

Don't forget to return .FirstOrDefault() as the Find result will be an IEnumerable<T>.

G0dsquad
  • 4,230
  • 1
  • 17
  • 22