1

I've read that I shouldn't be using same db context in a multi thread app.

so here is my scenario: I have 2 functions that I run for each years, and each function call sub functions multiple times depending on the row count.

The goal here is : If there are new records add it to the database otherwise update some fields of the record.

What I do is:

1- await StaticSettings.CACHED_DATA.FillAll(); Caches the POCO classes I need into lists. (I'm doing this because I thought that it would be faster to check the records from a cached context rather than using linq on dbcontext multiple times.

2- I run the below code. and Inside it I compare data with cached data

await GetAllData(cookie, datTypes.Select(x => x.DMT_CODE).ToList(), "me", year.Y_YEAR);
await GetAllData(cookie, datTypes.Select(x => x.DMT_CODE).ToList(), "they", year.Y_YEAR);

3- When all tasks are done I call to save changes and dispose objects..

await StaticSettings.CACHED_DATA.ProcessTasks(); //Saves

so What I would like to know is if I can rely on this code..

            Trace.WriteLine($@"Caching data");
            await StaticSettings.CACHED_DATA.FillAll();
            Trace.WriteLine($@"Caching done");

            var ts = years.Select(year => Task.Run(async () =>
                {
                    Trace.WriteLine($"Login Start {year.Y_YEAR}");
                    var cookie = await MahkemeWebUtils.ForceLoginWebClient(user.MU_USERNAME, user.MU_PASSWORD);
                    Trace.WriteLine($"Login End {year.Y_YEAR}");


                    await GetAllData(cookie, datTypes.Select(x => x.DMT_CODE).ToList(), "me", year.Y_YEAR);
                    await GetAllData(cookie, datTypes.Select(x => x.DMT_CODE).ToList(), "they", year.Y_YEAR);

                    //GC.Collect();
                }))
                .ToList();

            await Task.WhenAll(ts);
            await StaticSettings.CACHED_DATA.ProcessTasks(); //Saves 

UPDATE

public class CACHED_DATA
{
    public AppStructMahkeme _db;
    public List<DAVALAR> DavaLarToProcess { get; set; } = new List<DAVALAR>();

    public List<KAZALAR> KazaList = new List<KAZALAR>();
    public List<DAVA_TURLERI> DavaTurList = new List<DAVA_TURLERI>();
    public List<DAVA_SCALE> DavaScaleList = new List<DAVA_SCALE>();
    public List<STATUSES> StatusList = new List<STATUSES>();
    public List<DAVA_KONULARI> DavakonuList = new List<DAVA_KONULARI>();
    public List<AVUKATLAR> AvukatList = new List<AVUKATLAR>();
    public List<EVRAK_TYPES> EvrakTypeList = new List<EVRAK_TYPES>();
    public List<SENDERS> SendersList = new List<SENDERS>();
    public List<ICRA_STATUS> IcraStatusList = new List<ICRA_STATUS>();
    public List<DAVALAR> DavaList = new List<DAVALAR>();
    public List<ISTIDA_TURLERI> IstidaTurList = new List<ISTIDA_TURLERI>();
    public List<ISTIDALAR> IstidaList = new List<ISTIDALAR>();
    public async Task FillAll()
    {

        _db = new AppStructMahkeme();
        DavaLarToProcess = new List<DAVALAR>();
        //_db.Configuration.LazyLoadingEnabled = false;
        //KazaList = null;
        KazaList = await _db.KAZALAR.ToListAsync();
        DavaTurList = await _db.DAVA_TURLERI.ToListAsync();
        DavaScaleList = await _db.DAVA_SCALE.ToListAsync();
        StatusList = await _db.STATUSES.ToListAsync();
        AvukatList = await _db.AVUKATLAR.ToListAsync();
        EvrakTypeList = await _db.EVRAK_TYPES.ToListAsync();
        SendersList = await _db.SENDERS.ToListAsync();
        IcraStatusList = await _db.ICRA_STATUS.ToListAsync();
        DavakonuList = await _db.DAVA_KONULARI.ToListAsync();
        DavaList = await _db.DAVALAR.ToListAsync();
        IstidaTurList = await _db.ISTIDA_TURLERI.ToListAsync();
        IstidaList = await _db.ISTIDALAR.ToListAsync();
    }





    public async Task ProcessTasks()
    {
        if(DavaLarToProcess.Count!=0)
             _db.DAVALAR.AddRange(DavaLarToProcess);

        Trace.WriteLine("saving");
        await _db.SaveChangesAsync();
        Trace.WriteLine("saved");



        _db.Dispose();

        DavaLarToProcess = null;
        KazaList = null;
        DavaTurList = null;
        DavaScaleList = null;
        StatusList = null;
        AvukatList = null;
        EvrakTypeList = null;
        SendersList = null;
        IcraStatusList = null;
        DavakonuList = null;
        DavaList = null;
        IstidaTurList = null;
        IstidaList = null;
    }
}
Asım Gündüz
  • 1,257
  • 3
  • 17
  • 42
  • 2
    *Don't* try to use a DbContext or a connection among threads. It's not a cache, it's a Unit of Work. Create the context only where you need it and dispose of it as soon as possible. The best way is to use a `using` block – Panagiotis Kanavos Jun 20 '19 at 12:30
  • BTW there's no context in your code, unless it's `CACHED_DATA` – Panagiotis Kanavos Jun 20 '19 at 12:32
  • yes it's declared inside it – Asım Gündüz Jun 20 '19 at 12:32
  • In that case why post that code? It doesn't show multithreaded access of a context. – Panagiotis Kanavos Jun 20 '19 at 12:33
  • Why do you want to use a context from multiple threads in the first place? It won't speed up bad queries or make inappropriate use cases go faster. ORMs are inappropriate for bulk importing for example. Saving changes one object at a time is always going to be slower than using calling `SaveChanges` only once all relevant changes are made to the DbContext. In many cases you can improve performance immensely by using the correct technique, while *multithreading* can seriously harm performance and reliability eg by increasing conflicts, blocking and deadlocks – Panagiotis Kanavos Jun 20 '19 at 12:36
  • I don't want to use singleton dbContext from multi threads. I fetch data from db context outside of the multi thread and I would like to know if it is safe to use linq on fetched data while in mutli thread. I'm sorry for my bad english – Asım Gündüz Jun 20 '19 at 12:39
  • English isn't the problem. The *code* is missing. If you create and use the context inside each of the methods that load the data only *one* thread will use it. – Panagiotis Kanavos Jun 20 '19 at 12:43
  • DbContext instance is not used in the multithread the only thing I do in multi thread is use linq on earlier fetched DbSets(outside of multi thread) and when multi thread finish, I run savechanges. – Asım Gündüz Jun 20 '19 at 12:48
  • `on earlier fetched DbSets` those aren't data, they aren't fetched. They represent *entities* and are used as the base to construct LINQ queries. Data is fetched *only* when the call to `ToList()` or `ToListAsync()` is made. Post your code, don't describe it. BTW if `datTypes` is a DbSet, every time you call `datTypes.Select(x => x.DMT_CODE).ToList()` you execute *another* query that loads exactly the same data as the previous one – Panagiotis Kanavos Jun 20 '19 at 12:49
  • Possible duplicate of [Is DbContext thread safe?](https://stackoverflow.com/questions/6126616/is-dbcontext-thread-safe) – Clint Jun 20 '19 at 12:56

0 Answers0