views:

225

answers:

4

If I have a static method like this

    private static bool TicArticleExists(string supplierIdent)
    {
        using (TicDatabaseEntities db = new TicDatabaseEntities())
        {
            if((from a in db.Articles where a.SupplierArticleID.Equals(supplierIdent) select a).Count() > 0)
                return true;                
        }
        return false;
    }

and use this method in various places in foreach loops or just plain calling it numerous times, does it create and open new connection every time?

  1. If so, how can I tackle this? Should I cache the results somewhere, like in this case, I would cache the entire Classifications table in Memory Cache? And then do queries vs this cached object?
  2. Or should I make TicDatabaseEntities variable static and initialize it at class level?
  3. Should my class be static if it contains only static methods? Because right now it is not..
  4. Also I've noticed that if I return result.First() instead of FirstOrDefault() and the query does not find a match, it will issue an exception (with FirstOrDefault() there is no exception, it returns null).

Thank you for clarification.

+1  A: 
  • new connections are non-expensive thanks to connection caching. Basically, it grabs an already open connection (I htink they are kept open for 2 minutes for reuse).

  • Still, caching may be better. I do really not like the "firstordefault". Thinks of whether you can acutally pull in more in ONE statement, then work from that.

For the rest, I can not say anything - too much depends on what you actually do there logically. What IS TicDatabaseEntities? CAN it be cached? How long? Same with (3) - we do not know because we do not know what else is in there.

If this is something like getting just some lookup strings for later use, I would say....

  • Build a key out of classI, class II, class III
  • load all classifications in (I assume there are only a couple of hundred)
  • Put them into a static / cached dictionary, assuming they normally do not change (and I htink I have that idea here - is this a financial tickstream database?)

Without business knowledge this can not be answered.

4: yes, that is as documented (RTFM hint). First gives first or an exception, FirstOrDefault defaults to default (empty struct initialized with 0, null for classes).

TomTom
TicDatabaseEntities is an Entity Data Model (EF) context.Could you explain in more detail why don't you like firstordefault()?
mare
A: 

Thanks Dan and TomTom, I've came up with this. Could you please comment this if you see anything out or the order?

    public static IEnumerable<Article> TicArticles
    {
        get
        {
            ObjectCache cache = MemoryCache.Default;
            if (cache["TicArticles"] == null)
            {
                CacheItemPolicy policy = new CacheItemPolicy();
                using(TicDatabaseEntities db = new TicDatabaseEntities())
                {
                    IEnumerable<Article> articles = (from a in db.Articles select a).ToList();
                    cache.Set("TicArticles", articles, policy);
                }
            }

            return (IEnumerable<Article>)MemoryCache.Default["TicArticles"];
        }
    }


    private static bool TicArticleExists(string supplierIdent)
    {
        if (TicArticles.Count(p => p.SupplierArticleID.Equals(supplierIdent)) > 0)
            return true;
        return false;
    }

If this is ok, I'm going to make all my method follow this pattern.

mare
A: 

does it create and open new connection every time?

No. Connections are cached.

Should I cache the results somewhere

No. Do not cache entire tables.

should I make TicDatabaseEntities variable static and initialize it at class level?

No. Do not retain a DataContext instance longer than a UnitOfWork.

Should my class be static if it contains only static methods?

Sure... doing so will prevent anyone from creating useless instances of the class.

Also I've noticed that if I return result.First() instead of FirstOrDefault() and the query does not find a match, it will issue an exception

That is the behavior of First. As such - I typically restrict use of First to IGroupings or to collections previously checked with .Any().


I'd rewrite your existing method as:

using (TicDatabaseEntities db = new TicDatabaseEntities()) 
{
  bool result = db.Articles
    .Any(a => a.supplierArticleID.Equals(supplierIdent));

  return result;
}

If you are calling the method in a loop, I'd rewrite to:

private static Dictionary<string, bool> TicArticleExists
  (List<string> supplierIdents)   
{
  using (TicDatabaseEntities db = new TicDatabaseEntities())   
  {   
    HashSet<string> queryResult = new HashSet(db.Articles
      .Where(a => supplierIdents.Contains(a.supplierArticleID))
      .Select(a => a.supplierArticleID));

    Dictionary<string, bool> result = supplierIdents
      .ToDictionary(s => s, s => queryResult.Contains(s));

    return result;
  }
}
David B
very nice, thank you!
mare
After accepting your answer, I found out that the first piece of code you provided (using Any()) takes much longer to execute vs my previous code based on Count().The second method has some issue too - specifically it timeouts when making the HashSet.
mare
Use db.Log = Console.Out; to dump out the query used. Find the difference in the query.
David B
A: 

I'm trying to find the article where I read this, but I think it's better to do (if you're just looking for a count):

from a in db.Articles where a.SupplierArticleID.Equals(supplierIdent) select 1

Also, use Any instead of Count > 0.

Will update when I can cite a source.

Tim Ridgely