views:

60

answers:

1

My program has the following class definition:

public sealed class Subscriber
{
    private subscription;
    public Subscriber(int id)
    {
        using (DataContext dc = new DataContext())
        {
           this.subscription = dc._GetSubscription(id).SingleOrDefault();                
        }            
    }
}

,where

_GetSubscription() is a sproc which returns a value of type ISingleResult<_GetSubscriptionResult>

Say, I have a list of type List<int> full of 1000 ids and I want to create a collection of subscribers of type List<Subscriber>.

How can I do that without calling the constructor in a loop for 1000 times?

Since I am trying to avoid switching the DataContext on/off so frequently that may stress the database.

TIA.

+6  A: 

Write a static factory method which calls a private constructor.

public sealed class Subscriber
{
    // other constructors ...

    // this constructor is not visible from outside.
    private Subscriber(DataContext dc, int id)
    {
       // this line should probably be in another method for reusability.
       this.subscription = dc._GetSubscription(id).SingleOrDefault();                
    }

    public List<Subscriber> CreateSubscribers(IEnumerable<int> ids)
    {
        using (DataContext dc = new DataContext())
        {

           return ids
             .Select(x => new Subscriber(dc, x))
             // create a list to force execution of above constructor
             // while in the using block.
             .ToList();
        }            

    }

}
Stefan Steinegger
Hi Stefan,Your answer is really cool. However I got a System.ObjectDisposedException as the DataContext dc is disposed.System.ObjectDisposedException was unhandled Message="Cannot access a disposed object.\r\nObject name: 'DataContext accessed after Dispose.'." Source="System.Data.Linq" ObjectName="DataContext accessed after Dispose."Thanks
codemonkie
I tried saving a local copy of the return value but that still doesn't work.
codemonkie
I managed to get it to work by doing something like.....return ids.select(x => new Subscriber(dc, x)).ToList();But I'm confused what's going on here. One thing that I'm pretty sure is that the IEnumerable<Subscriber>'s life time is tied with the DataContext.
codemonkie
Yes, sorry, I fixed it. The problem is that the lambda expression is executed when accessing the `IEnumerable` (from the caller). A common mistake when working with `IEnumerables`.
Stefan Steinegger
Thanks a lot Stefan for your solution, that really helps, I know that's the so-called "deferred execution" in LINQ to SQL, but still want to know why IEnumerable is gone with the DataContext, even a reference is saved.
codemonkie
It's not the deferred execution of LINQ to SQL, there is not LINQ to SQL involved here. It's the problem of the `Select(x => ...)`. The lambda expression is not executed in this line of code. The lambda is a delegate, it is just a reference to a "piece of code", which is not executed yet. It will be executed in the `foreach` statement, which gets the items from the IEnumerable. Just put a breakpoint to the lambda expression (not the select, but the lambda), and see it in the debugger.
Stefan Steinegger