简体   繁体   中英

Entity framework with Linq to Entities performance

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.

  • 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. First gives first or an exception, FirstOrDefault defaults to default (empty struct initialized with 0, null for classes).

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.

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;
  }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM