Search code examples
c#sqlstrongly-typed-dataset

Do I write these using statements inside or outside the class?


I have a class that I wrote that contains different methods that perform calculations on data pulled from my database. Each method pulls information from the database and performs calculations on it and then saves it to a variable in the class that I can access when I initialize the class. I have two pseudo code methods below and I'm trying to figure out the following:

  1. Which way should I utilize the using statements if every method pulls data and then performs calculations on it?
  2. Am I using the most efficient way to store the data?

This is what I do when I initialize the class

    public class Calculations
    {
    public string Symbol { get; set; }
    public string Market { get; set; }
    public List<decimal> stockPctReturns { get; set; }
    public List<decimal> marketPctReturns { get; set; }
    public enum returnType { Market, Stock };
    public decimal avgAnnualMarketGrowth { get; set; }
    public List<decimal> stockPctGains { get; set; }
    public List<decimal> stockPctLosses { get; set; }
    public List<decimal> positiveMoneyFlow { get; set; }
    public List<decimal> negativeMoneyFlow { get; set; }
    public decimal rsi { get; set; }
    public decimal mfi { get; set; }
    public decimal williamsR { get; set; }
    public decimal sma20 { get; set; }
    public decimal sma50 { get; set; }
    public decimal sma200 { get; set; }
    public const decimal riskFree10Yr = 2.58M;

    public Calculations(string symbol, string market)
    {
        // initialize everything in the class
        Symbol = symbol;
        Market = market;
    }
}

Do it this way:

public void fillPctReturns()
    {
        stockPctReturns = new List<decimal>();
        marketPctReturns = new List<decimal>();

        using (DailyGlobalDataTableAdapter dailyGlobalAdapter = new DailyGlobalDataTableAdapter())
        using (DailyAmexDataTableAdapter dailyAmexAdapter = new DailyAmexDataTableAdapter())
        using (DailyGlobalDataTable dailyGlobalTable = new DailyGlobalDataTable())
        using (DailyAmexDataDataTable dailyAmexTable = new DailyAmexDataDataTable())
        {
            dailyAmexAdapter.Fill(dailyAmexTable);
            dailyGlobalAdapter.Fill(dailyGlobalTable);
                    var amexQuery = from c in dailyGlobalTable.AsEnumerable()
                                    where c.Date >= DateTime.Now.Subtract(TimeSpan.FromDays(60))
                                    orderby c.Date descending
                                    join d in dailyAmexTable.AsEnumerable() on c.Date equals d.Date
                                    select new StockMarketCompare { stockClose = d.AdjustedClose, marketClose = c.AdjustedClose };

                    List<StockMarketCompare> amexResult = amexQuery.ToList();
// perform calculations here and save to stockPctReturns and marketPctReturns
         }
  }

Or should I do it this way:

using (DailyGlobalDataTableAdapter dailyGlobalAdapter = new DailyGlobalDataTableAdapter())
        using (DailyAmexDataTableAdapter dailyAmexAdapter = new DailyAmexDataTableAdapter())
        {
            Calculations calc = new Calculations();
            calc.Symbol = "GOOG";
            calc.Market = "nyse";
            dailyAmexAdapter.Fill(calc.dailyAmexTable);
            dailyGlobalAdapter.Fill(calc.dailyGlobalTable);
            calc.fillPctReturns();
        }

// this example would have public properties in the calculations class for the datatables and as you can see I set them like the above

Hopefully you can tell what I'm trying to do.


Solution

  • It looks like the second method you show does now allow you to wrap dailyAmexTable and dailyGlobalTable in using blocks, so if their respective classes implement IDisposable (which I assume they do based on your other code), then I would prefer the first method. This allows you to wrap all of your IDisposable instances in using blocks, which you should be doing.

    The main thing with using blocks is that you generally want to close them as soon as you don't need them anymore in order to free up resources. As such, you should try to do your calculations outside the using block, unless you need to save something back to the database after performing calculations. So it would look something like this:

    public void fillPctReturns()
    {
        stockPctReturns = new List<decimal>();
        marketPctReturns = new List<decimal>();
    
        // Declare amexResult here so it is accessible outside the using block
        List<StockMarketCompare> amexResult;
    
        using (DailyGlobalDataTableAdapter dailyGlobalAdapter = new DailyGlobalDataTableAdapter())
        using (DailyAmexDataTableAdapter dailyAmexAdapter = new DailyAmexDataTableAdapter())
        using (DailyGlobalDataTable dailyGlobalTable = new DailyGlobalDataTable())
        using (DailyAmexDataDataTable dailyAmexTable = new DailyAmexDataDataTable())
        {
            dailyAmexAdapter.Fill(dailyAmexTable);
            dailyGlobalAdapter.Fill(dailyGlobalTable);
            var amexQuery = from c in dailyGlobalTable.AsEnumerable()
                            where c.Date >= DateTime.Now.Subtract(TimeSpan.FromDays(60))
                            orderby c.Date descending
                            join d in dailyAmexTable.AsEnumerable() on c.Date equals d.Date
                            select new StockMarketCompare { stockClose = d.AdjustedClose, marketClose = c.AdjustedClose };
    
            amexResult = amexQuery.ToList();
    
         }
         // perform calculations here and save to stockPctReturns and marketPctReturns
    }
    

    EDIT:

    Now that I see what you are doing more clearly, I would recommend having the using blocks outside of the class. the main reason is to make sure your code is loosely coupled, in this case meaning that the data access code is separate from the business logic (a.k.a calculations) code. One way to do this is to run your query outside of the calculations class, and pass the query result to a property in the calculations class. For example:

    public class Calculations
    {
        public List<StockMarketCompare> Data { get; set; }
        // (Other properties and methods omitted.)
    }
    

    Then in your calling function:

    var calc = new Calculations();
    using (DailyGlobalDataTableAdapter dailyGlobalAdapter = new DailyGlobalDataTableAdapter())
    using (DailyAmexDataTableAdapter dailyAmexAdapter = new DailyAmexDataTableAdapter())
    using (DailyGlobalDataTable dailyGlobalTable = new DailyGlobalDataTable())
    using (DailyAmexDataDataTable dailyAmexTable = new DailyAmexDataDataTable())
    {
        dailyAmexAdapter.Fill(dailyAmexTable);
        dailyGlobalAdapter.Fill(dailyGlobalTable);
        var amexQuery = from c in dailyGlobalTable.AsEnumerable()
                        where c.Date >= DateTime.Now.Subtract(TimeSpan.FromDays(60))
                        orderby c.Date descending
                        join d in dailyAmexTable.AsEnumerable() on c.Date equals d.Date
                        select new StockMarketCompare { stockClose = d.AdjustedClose, marketClose = c.AdjustedClose };
    
        calc.Data = amexQuery.ToList();
        calc.fillPctReturns();
        // Run any other calculations here.
        // Save data to DB here.
    }