While refactoring code I stumbled upon some stacked using statements (I'm talking about 10 to 15-ish).
using(X x=new X())
using(Y y=new Y())
using(Z z=new Z())
using(...)
{
List<X> listX= x.GetParameterListByID(pID);
List<Y> listY=y.GetParameterListByID(pID);
...
...
//other (business) calls/code, like 20-30 lines, that don't need the using instances
}
Class example would be something like
public class X : IDisposable{
public List<XParameterInfo> GetParameterListByID(int? pID){
const string query="SELECT name,value FROM parameters WHERE id=#ID";
//query code here
return queryResult;
}
}
And the first thing I thought of was, knowing that a using is basicly a try{} finally{ x.Dispose(); }, that the using connections would be kept open/active untill the code within the using block is finished while it is only needed to fill one list.
The above is what I assume, correct me if I'm wrong.
Considering what I said is correct, would it be better (performance, but mostly good practice-wise) to write something like
List<X> listX;
List<Y> listY;
List<Z> listZ;
...
//for the example here I wrote out 3 but let's talk 10 or more
using(X x=new X())
{
listX=x.GetParameterListByID(pID);
}
using(Y y=new Y())
{
listY=y.GetParameterListByID(pID);
}
using(Z z=new Z())
{
listZ=z.GetParameterListByID(pID);
}
...
// other calls but now outside the using statements
or is it negligible, other than the fact that stacked using statements take away the nested code look?
would it be better (performance wise)
that depends on the types that are used in the using. You can't make a general statement.
Performance is not the only factor, open resources can block other processes or cause memory issues. But on the other side readability is increased with the more compact first version. So you have to decide if there is an issue at all. If not, why bother? Then chose the best readable and maintainable code.
But you could refactor your code, use a method to encapsulate the usings:
// in class X:
public static List<X> GetParameterListByID(int pID)
{
using(X x = new X())
{
return x.GetParameterListByID(pID);
}
}
// and same in other classes
Now the code has no usings:
List<X> listX = X.GetParameterListByID(pID); // static method called
List<Y> listY = Y.GetParameterListByID(pID); // static method called
In addition to what Tim said, many DB drivers use "Connection Pooling" to increase the performance of connections, by reusing old ones. So when Dispose is called upon connections, they don't really close (except after certain conditions are met), but they are kept idle for subsequent calls.
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/connection-pooling
Why don't you use 1 connection for all the queries?
I think this would be a more elegant solution.
void Main()
{
List<X> listX;
List<Y> listY;
List<Z> listZ;
using(SqlConnection conn = new SqlConnection())
{
conn.Open();
listX=new X().GetParameterListByID(conn, pID);
listY=new Y().GetParameterListByID(conn, pID);
listZ=new Z().GetParameterListByID(conn, pID);
}
}
Related
For simple lookups, I need to perform some SQL statements on a DB2 machine. I'm not able to use an ORM at the moment. I have a working example through this code, however I'm wondering if it can be optimized more as this would essentially create a connection on each request. And that just seems like bad programming.
Is there a way I can optimize this Get() request to leave a connection open? Nesting using statements seems dirty, as well. How should I handle the fact that Get() really wants to return an object of User no matter what; even in error? Can I put this connection in the start of the program so that I can use it over and over again? What are some of the best practices for this?
public class UsersController : ApiController
{
String constr = WebConfigurationManager.ConnectionStrings["DB2Connection"].ConnectionString;
public User Get([FromUri] User cst)
{
if (cst == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
else
{
using (OdbcConnection DB2Conn = new OdbcConnection(constr))
{
DB2Conn.Open();
using (OdbcCommand com = new OdbcCommand(
// Generic SQL Statement
"SELECT * FROM [TABLE] WHERE customerNumber = ?", DB2Conn))
{
com.Parameters.AddWithValue("#var", cst.customerNumber);
using (OdbcDataReader reader = com.ExecuteReader())
{
try
{
while (reader.Read())
{
cst.name = (string)reader["name"];
return cst;
}
}
catch
{
throw;
}
}
}
}
return cst;
}
}
}
I found a great question that doesn't really have detailed answers, I feel like similar solutions exist for both of these questions...
And that just seems like bad programming.
Why do you think that?
The underlying system should be maintaining connections in a connection pool for you. Creating a connection should be very optimized already.
From a logical perspective, what you're doing now is exactly what you want to be doing. Create the connection, use it, and dispose of it immediately. This allows other threads/processes/etc. to use it from the connection pool now that you're done with it.
This also avoids the myriad of problems which arise from manually maintaining your open connections outside of the code that uses them.
Is there a way I can optimize this Get() request to leave a connection open?
Have you measured an actual performance problem? If not, there's nothing to optimize.
And there's a very good chance that hanging on to open connections in a static context in your web application is going to have drastic performance implications.
In short... You're already doing this correctly. (Well, except for that unnecessary try/catch. You can remove that.)
Edit: If you're just looking to improve the readability of the code (which itself is a matter of personal preference), this seems readable to me:
public User Get([FromUri] User cst)
{
if (cst == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
using (var DB2Conn = new OdbcConnection(constr))
using (var com = new OdbcCommand("SELECT * FROM [TABLE] WHERE customerNumber = ?", DB2Conn))
{
com.Parameters.AddWithValue("#var", cst.customerNumber);
DB2Conn.Open();
using (OdbcDataReader reader = com.ExecuteReader())
while (reader.Read())
{
cst.name = (string)reader["name"]
return cst;
}
}
return cst;
}
Note that you can further improve it by re-addressing the logic of that SQL query. Since you're fetching one value from one record then you don't need to loop over a data reader. Just fetch a single literal and return it. Note that this is free-hand and untested, but it might look something like this:
public User Get([FromUri] User cst)
{
if (cst == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
using (var DB2Conn = new OdbcConnection(constr))
using (var com = new OdbcCommand("SELECT name FROM [TABLE] WHERE customerNumber = ? FETCH FIRST 1 ROWS ONLY", DB2Conn))
{
com.Parameters.AddWithValue("#var", cst.customerNumber);
DB2Conn.Open();
cst.name = (string)com.ExecuteScalar();
}
return cst;
}
#David's answer addresses your actual questions perfectly but here's some other observations that may make your code a little more pallatable to you:
remove the try/catch block - all you're doing is re-throwing the exception which is what will happen if you don't use a try/catch at all. Don't catch the exception unless you can do something about it. (I see now that #David's answer addresses that - either it was added after I read it or I missed it - my apologies for the overlap but it's worth reinforcing)
Change your query to just pull name and use ExecuteScalar instead of ExecuteReader. You are taking the name value from the first record and exiting the while loop. ExecuteScalar returns the value from the first column in the first record, so you can eliminate the while loop and the using there.
I gotta run a maybe one-time or potentially once every few months update on this table. Basically to allow other programs that reference to run faster. I really thought this update looked right but it did not change the data. Is what I am doing wrong?
public static void UpdateMFGtoID()
{
DataDataContext _db = new DataDataContext();
foreach (VINPatternDecode vin in _db.VINPatternDecodes)
{
vin.DivisionName = GetMfgID(vin.DivisionName.Replace("~",""));
_db.SubmitChanges();
}
}
It should work, but its better to Dispose your resources, and maybe, depending on the amount of data (if its small) just use one SubmitChanges():
using (DataDataContext _db = new DataDataContext())
{
foreach (VINPatternDecode vin in _db.VINPatternDecodes)
{
vin.DivisionName = GetMfgID(vin.DivisionName.Replace("~",""));
}
_db.SubmitChanges();
}
The using calls the Dispose function implicit.
I basically have created a class which when a user logs into a website it then queries the database and stores some settings in a List (So I have key/pair values).
The reason for this is because I want to always be able to access these settings without going to the database again.
I put these in a class and loop through the fields via a SQL query and add them to the list.
How can I then access these variables from another part of the application? or is there a better way to do this? I'm talking server side and not really client side.
Here is an example of what I had at the moment:
public static void createSystemMetaData()
{
string constring = ConfigurationManager.ConnectionStrings["Test"].ConnectionString;
SqlConnection sql = new SqlConnection(constring);
sql.Open();
SqlCommand systemMetaData = new SqlCommand("SELECT * FROM SD_TABLES", sql);
//Set Modules
using (SqlDataReader systemMetaDataReader = systemMetaData.ExecuteReader())
{
while (systemMetaDataReader.Read())
{
var name = systemMetaDataReader.GetOrdinal("Sequence").ToString();
var value = systemMetaDataReader.GetOrdinal("Property").ToString();
var Modules = new List<KeyValuePair<string, string>>();
Modules.Add(new KeyValuePair<string, string>(name, value));
}
}
}
Thanks
Any static properties of a class will be preserved for the lifetime of the application pool, assuming you're using ASP.NET under IIS.
So a very simple class might look like:
public static class MyConfigClass
{
public static Lazy<Something> MyConfig = new Lazy<Something>(() => GetSomethings());
public static Something GetSomethings()
{
// this will only be called once in your web application
}
}
You can then consume this by simply calling
MyConfigClass.MyConfig.Value
For less users you can go with the SessionState as Bob suggested,however with more users you might need to move to a state server or load it from Data Base each time.
As others have pointed out, the risk of holding these values in global memory is that the values might change. Also, global variables are a bad design decision as you can end up with various parts of your application reading and writing to these values, which makes debugging problems harder than it need be.
A commonly adopted solution is to wrap your database access inside a facade class. This class can then cache the values if you wish to avoid hitting the database for each request. In addition, as changes are routed through the facade too, it knows when the data has changed and can empty its cache (forcing a database re-read) when this occurs. As an added bonus, it becomes possible to mock the facade in order to test code without touching the database (database access is notoriously difficult to unit test).
From the looks of things you are using universal values irrespective of users so an SqlCacheDependency would be useful here:
Make sure you setup a database dependency in web.config for the name Test
public static class CacheData {
public static List<KeyValuePair<string,string>> GetData() {
var cache = System.Web.HttpContext.Current.Cache;
SqlCacheDependency SqlDep = null;
var modules = Cache["Modules"] as List<KeyValuePair<string,string>>;
if (modules == null) {
// Because of possible exceptions thrown when this
// code runs, use Try...Catch...Finally syntax.
try {
// Instantiate SqlDep using the SqlCacheDependency constructor.
SqlDep = new SqlCacheDependency("Test", "SD_TABLES");
}
// Handle the DatabaseNotEnabledForNotificationException with
// a call to the SqlCacheDependencyAdmin.EnableNotifications method.
catch (DatabaseNotEnabledForNotificationException exDBDis) {
SqlCacheDependencyAdmin.EnableNotifications("Test");
}
// Handle the TableNotEnabledForNotificationException with
// a call to the SqlCacheDependencyAdmin.EnableTableForNotifications method.
catch (TableNotEnabledForNotificationException exTabDis) {
SqlCacheDependencyAdmin.EnableTableForNotifications("Test", "SD_TABLES");
}
finally {
// Assign a value to modules here before calling the next line
Cache.Insert("Modules", modules, SqlDep);
}
}
return modules;
}
I have created a PhoneBook style application; on my phonebook object I have a local member _site which is used as a filter, since there are approximately 1000 phone numbers, split across 12 sites within my organisation. Only one site will be retrieved at a time using this method.
This was my original method. The GUI has several methods for reordering the data, so I left it as an IQueryable because I would like to defer SQL to allow for filtering to be done on the SQL server rather than on the client PC.
Works
public IQueryable<PhoneNumber> GetPhoneDirectory()
{
PhoneBookDataContext db = new PhoneBookDataContext())
return db.PhoneNumbers.Where(d => d.Site == _site);
}
However, I am also trying to keep to 'best practise' in terms of using statements.
Doesn't Work
public IQueryable<PhoneNumber> GetPhoneDirectory()
{
using (PhoneBookDataContext db = new PhoneBookDataContext())
{
return db.PhoneNumbers.Where(d => d.Site == _site);
}
}
Now as pointed out by #justanotheruseryoumay, this will cause an exception because the datacontext is disposed by the time the objects are accessed.
I guess what I am asking is, how can I make sure my data context is disposed nicely, when I cannot use a 'using' statement and don't strictly know when the context is done with.
If you want to return IQueryable you can make your class that contains the GetPhoneDirectory disposable, make the PhoneBookDataContext a field, and dispose it in your dispose method.
You will then put the onus on the caller to dispose his instance of your class.
E.g.
public class MyClass : IDisposable
{
PhoneBookDataContext db;
public MyClass()
{
db = new PhoneBookDataContext();
}
public IQueryable<PhoneNumber> GetPhoneDirectory()
{
return db.PhoneNumbers.Where(d => d.Site == _site);
}
public void Dispose()
{
if (db != null)
{
db.Dispose();
db = null;
}
}
}
// Caller
using(var myClass = new MyClass())
{
var queryable = myClass.GetPhoneDirectory();
...
}
The execution of the query will still be deferred and the PhoneBookDataContext will still be properly Disposed because using is interpreted by the compile as a try/finally. When you actually execute the query it will result in a runtime error because the PhoneBookDataContext no longer exists. I would suggest doing a .ToList() on your query and returning it that way. If you want to change the order after you return it then you can still do LINQ on it as you please.
EDIT:
Another thing you could do is to create the using with the PhoneBookDataContext in the calling method and pass in the context. The context is really going to be used in that method anyway and you can keep it around as long as you need it and stick with the good using format.
Yes; It is bad design because your IQueryable<PhoneNumber> will be evaluated only when you call a method that cause it to be evaluated, like ToList() or when you iterate it with foreach.
in your code you are returning a IQueryable<PhoneNumber> which is not evaluated yet, and before the caller get any chance to execute it, it's internals that has the responsibility for yielding the records to you (db); is already disposed.
Just as a suggestion:
public IEnumerable<PhoneNumber> GetPhoneDirectory()
{
using (PhoneBookDataContext db = new PhoneBookDataContext())
{
return db.PhoneNumbers.Where(d => d.Site == _site).ToList();
}
}
Or relocate the db object to somewhere else in your design (Unit Of Work and Repository are nice patterns to get a look at IMHO).
I am new to developing in .NET and C#, but have been a long-time developer, working with C, C++, Java, PHP, etc.
I have an MVC3 extension class for my data models that refers to the database. It is set as "private static" in the class, but I think that it is not keeping up with database changes. In other words, when I change data in the controllers, those changes aren't "noticed" in the db because it is static. Currently, I am creating and disposing of the variable for each use, to compensate.
My questions are:
Am I correct that a static db variable could behave that way?
Is it necessary to dispose of the dynamic variable in the static class, or will garbage collection still take care of it automatically?
Here is a relevant snippet of the class:
namespace PBA.Models {
using System;
using System.Text.RegularExpressions;
using PBA.Models;
using PBA.Controllers;
public static class Extensions {
private static PbaDbEntities db = null;
public static PbaDbEntities GetDb() {
// TODO: find out about static memory/disposal, etc.
//
if (db != null) {
db.Dispose();
}
db = new PbaDbEntities();
return db;
}
public static string GetCheckpointState(this Activity activity, long memberProjectId) {
GetDb(); // TODO: Do I need to do this each time, or will a one-time setting work?
string state = CheckpointController.CHECKPOINT_STATUS_NOT_STARTED;
try {
var sub = db.ActivitySubmissions.
Where(s => s.activityId == activity.activityId).
Where(s => s.memberProjectId == memberProjectId).
OrderByDescending(s => s.submitted).
First();
if (sub != null) {
state = sub.checkpointStatusId;
}
}
catch (Exception e) {
// omitted for brevity
}
return state;
}
}
}
Your code will fail horribly in production.
DataContexts are not thread-safe; you must not share a context between requests.
Never put mutable objects in static fields in multi-threaded applications.
Ignoring exceptions that way is a terrible idea, if you don't want to handle exceptions just don't try/catch, or catch & rethrow. Think about it like this, after you've buried the exception, your program is in an invalid state, b/c something you have no control over error'd out. Now, b/c you've buried the exception, your program can continue to operate but it's in a bad state.
If your code makes it to production, 3.5 yrs from now some jr. programmer is going to get involved in some middle of the night firestorm because all of a sudden the website is broken, even though it used to work. It will be completely impossible to track down where the exception is happening so, this poor guy is going to spend 48 straight hours adding logging code all over the place to track down the problem. He will find that some DBA somewhere decided to rename the column MemberProjectId to MemberProjectIdentifier, which caused your linq to blow up.
Think of the children, handle exceptions, don't bury them.
btw - yes, i have been that guy that has to figure out these types of mistakes.
It seems like you need to read about mvc3 and entity framework before writing coding and asking in here for help on something that's coded full of bad practices.
Answering your questions:
1- no
2- makes no sense as the answer to 1
Do it right, here are some useful documentation: http://msdn.microsoft.com/en-us/library/ie/gg416514(v=vs.98).aspx
EDIT: Adding some explicit fix
You could access your dbcontext from an static class, something like this:
var context = DbProvider.CurrentDb;
The idea is to access your db from here always: from your extension methods and from your controller actions.
Then, the implementation of the DbProvider.CurrentDb will be something like this:
public static classDbProvider {
public static void Initialize(){
HttpContext.Current.ApplicationInstance.BeginRequest += CreateDb;
HttpConetxt.Current.ApplicationInstance.EndRequest += DisposeDb;
}
private static void CreateDb(object sender, EventArgs e) {
HttpContext.Items.Add("CurrentDb", new PbaDbEntities(););
}
private static void DisposeDb(object sender, EventArgs e)
{
Current.Dispose();
HttpContext.Items.Remove("CurrentDb");
}
public static PbaDbEntities CurrentDb{
get {
return (PbaDbEntities)HttpContext.Current.Items["CurrentDb"];
}
}
}
As you can see, it will create a new Db per each request and it will be available ONLY in that request. In that way, your db will be disposed at the end of each request. This pattern is called Open-Session-in-View.
Finally, you need to initialize the DbProvider calling the method
Initialize() in your Global.asax file, in the event Application_start.
Hope it helps.
I don't have any idea of the context here-- if db is simply a connection-like object or not, but it appears you are throwing away and recreating whatever it is unnecessarily.
Best to create a property (for whatever your doing) so to be consistent.
private static Thing _thing;
private static Thing thing{
get{
if(_thing==null){
_thing=new Thing();
}
return _thing;
}
}