How to connect to a database in ASP.NET? - asp.net

I moved to ASP.NET from PHP where the queries are run directly. So I always create Connection in the Page_Load Event, dispose it after I do all stuff needed, and access data with NpgsqlCommand. (Yes, I use Postgresql in my ASP.NET applications.)
After starting to learn ASP.NET MVC I was amazed how easy it is to access SQL with the LINQ to SQL thing. But... It works only with MS SQL. So my question is how to implement the same functionality in my applications? How to connect to databases easily?
I wrote my own wrapper classes for connecting to Postgresql. 1 class per a table.
This is a part of the Student class:
public class Student : User
{
private static NpgsqlConnection connection = null;
private const string TABLE_NAME = "students";
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
/// <summary>
/// Updates the student
/// </summary>
public void Update()
{
Connect();
Run(String.Format("UPDATE " + TABLE_NAME + " SET first_name='{0}', last_name='{1}', password='{2}' WHERE id={3}", FirstName, LastName, Password, Id));
connection.Dispose();
}
/// <summary>
/// Inserts a new student
/// </summary>
public void Insert()
{
Connect();
Run(String.Format("INSERT INTO " + TABLE_NAME + " (first_name, last_name, password) VALUES ('{0}', '{1}', '{2}')",FirstName, LastName, Password));
connection.Dispose();
}
private static void Run(string queryString)
{
NpgsqlCommand cmd = new NpgsqlCommand(queryString, connection);
cmd.ExecuteScalar();
cmd.Dispose();
}
private static void Connect()
{
connection = new NpgsqlConnection(String.Format("Server=localhost;Database=db;Uid=uid;Password=pass;pooling=false"));
connection.Open();
}
//....
So as you see the problem here is that with every INSERT, DELETE, UPDATE request I'm using Connect() method which connects to the database. I didn't realize how stupid it was before I had to wait for 10 minutes to have 500 rows inserted, as there were 500 connections to the database.
Using pooling while connecting does help, but still making the connection and making the server check the pool during every single query is stupid.
So I decided to move Connection property to a static DB class, and it didn't work either, because it's a really bad idea to store such objects as connections in a static class.
I really don't know what to do know. Yes, there's an option of manullay creating the connections in every Page_Load event and close them in the end like I'm doing it right now.
Student student = new Student { FirstName="Bob", LastName="Black" };
NpgsqlConnection connection = ... ;
student.Insert(connection);
But this code is pretty ugly. I will be really thankful to somebody who can hep me here.

I would not recommend this design. It is better to encapsulate each database call which means each call opens a new connection each time you need to do something on the db. This might sound inefficient if it were not for connection pooling. ASP.NET will reuse connections automatically for you in a pool. The problem in your design is that there is nothing that guarantees that the connection will be closed.
Thus, you should try something like
private static void Insert()
{
var sql = "Insert Into "....;
ExecuteActionQuery(sql);
}
private static void ExecuteActionQuery( string query )
{
using (var conn = new NpgsqlConnection(String.Format(connString))
{
conn.Open();
using ( var cmd = new NpgsqlCommand(query, connection) )
{
cmd.ExecuteNonQuery();
}
}
}
I typically make a few global functions that encapsulate the standard operations so that I need only pass a query and parameters and my method does the rest. In my example, my ExecuteActionQuery does not take parameters but this was for demonstration only.

Not really pertaining to your question but another solution, if you like linq to sql, you could try DBLinq which provides a Linq to SQL provider for Postgresql and others databases.
http://code.google.com/p/dblinq2007/

Related

Sharing Db Connection Across POCOs in ASP.NET 5 (vNext)

I'm learning how to use ASP.NET 5 (vNext). In an attempt to do this, I'm working on a basic application. In this application, I'm trying to connect to the database from a couple of POCOs (Customer, Order, etc.) using Dapper. If I understand things correctly, its expensive to create, connect to, and tear down connections to a database. If this is true, I'm trying to figure out the recommended way to share a connection across multiple objects.
Currently, I have the following:
public class Order
{
private IDbConnection _connection;
public void Save()
{
using (_connection = new SqlConnection("[MyConnectionString]")
{
_connection.Open();
_connection.Execute("[INSERTION SQL]");
}
}
public List<Order> FindByCustomerEmailAddress(string emailAddress)
{
using (_connection = new SqlConnection("[MyConnectionString]")
{
_connection.Open();
return _connection.Query<List<Order>>("SELECT o.* FROM Order o, Customer c WHERE o.CustomerId=c.CustomerId AND c.EmailAddress='" + emailAddress + "'" );
}
}
}
public class Customer
{
private IDbConnection _connection;
public void Save()
{
using (_connection = new SqlConnection("[MyConnectionString]")
{
_connection.Open();
_connection.Execute("[INSERTION SQL]");
}
}
public Customer FindByEmailAddress(string emailAddress)
{
using (_connection = new SqlConnection("[MyConnectionString]")
{
_connection.Open();
return _connection.Query<Customer>("SELECT * FROM Customer WHERE EmailAddress='" + emailAddress + "'" );
}
}
}
I thought about creating a Database class that looks like this:
public static class Database
{
private static IDbConnection Connection { get; set; }
public static IDbConnection GetConnection()
{
if (Connection == null)
{
Connection = new SqlConnection("[MyConnectionString]");
Connection.Open();
}
return Connection;
}
}
public class Order
{
public void Save()
{
var connection = Database.GetConnection();
connection.Execute("[INSERTION SQL]");
}
public List<Order> FindByCustomerEmailAddress(string emailAddress)
{
var connection = Database.GetConnection();
return connection.Query<List<Order>>("SELECT ...");
}
}
However, after thinking about this, I'm not sure if this a good strategy for managing a database connection. The use of static in this manner seems dangerous. Yet, it seems like someone has had to solve this issue. But, nothing I've seen is explained so I do not understand if it actually works. Can someone share with me what the recommended approach for managing database connections in an efficient manner is?
Thank you!
Opening and closing connection to a database server is indeed expensive. However, .NET implements connection pooling just for this reason, and it is on by default. You can modify the setting of how many connection it should keep open (I don't recall the default).
So, if your connection string is the same, .NET will reuse an open connection from the pool and use that. If different, it'll create a new one.
Your first code is correct in using "using" so when you're done, the dispose/close will give the connection back to the pool.
See more about this here; https://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.110).aspx

NHibernate, SQLite and ATTACH DATABASE

I'm trying to do something slightly unusual... I currently have a SQLite database, accessed with NHibernate. This database is frequently uploaded to a server. I have a new requirement to create a new table for reporting purposes, which is expected to become pretty big. This table doesn't need to be uploaded to the server, so I'd like to put it in a separate database, and use ATTACH DATABASE to access it transparently from my main database.
The problem is I don't know how to do that with NHibernate... How can I tell NHibernate to attach the other database when it connects? I can't find any connection string parameter or NH configuration property allowing to do that... is it even possible?
An acceptable option would be to manually execute the ATTACH DATABASE command when the connection is open, but I don't know how to do that. When I build the NH session factory, it immediately tries to update the schema (hbm2ddl.auto = update), and I don't have an opportunity to do anything with the connection before that. So it will just try to create the new table on my main database, which of course is not what I want...
Has anybody ever done that before? How did you do it?
Thanks
EDIT: In case someone needs to do the same, here's my solution, inspired by Diego's answer
Connection provider:
public class AttachedDbConnectionProvider : DriverConnectionProvider
{
private string _attachedDbAlias;
private string _attachedDbFileName;
public override IDbConnection GetConnection()
{
var connection = base.GetConnection();
if (!string.IsNullOrEmpty(_attachedDbAlias) && !string.IsNullOrEmpty(_attachedDbFileName))
{
using (var attachCommand = connection.CreateCommand())
{
attachCommand.CommandText = string.Format(
"ATTACH DATABASE '{0}' AS {1}",
_attachedDbFileName.Replace("'", "''"),
_attachedDbAlias);
attachCommand.ExecuteNonQuery();
}
}
return connection;
}
public override void Configure(IDictionary<string, string> settings)
{
base.Configure(settings);
settings.TryGetValue("connection.attached_db_alias", out _attachedDbAlias);
settings.TryGetValue("connection.attached_db_filename", out _attachedDbFileName);
}
}
Configuration file:
<property name="connection.provider">MyApp.DataAccess.AttachedDbConnectionProvider, MyApp.DataAccess</property>
<property name="connection.attached_db_alias">reportdb</property>
<property name="connection.attached_db_filename">mydatabase.report.db</property>
Now, to map a class to a table in the attached database, I just need to specify "reportdb." in the mapping file
This might help...
public class MyConnectionProvider : DriverConnectionProvider
{
public override IDbConnection GetConnection()
{
var connection = base.GetConnection();
var attachCommand = connection.CreateCommand();
attachCommand.CommandText = "ATTACH DATABASE FOO";
attachCommand.ExecuteNonQuery();
return connection;
}
}
Config:
<property name="connection.provider">MyConnectionProvider, MyAssembly</property>

SubSonic 3 Repository - SQLite In-Memory

Before I invest the time in modifying the SubSonic 3 source, I figured I ask to see if I'm missing something simple.
Is it possible to use the SubSonic 3 Repository with migrations on a SQLite In-Memory database? I couldn't find a way to force the DbDataProvider to keep the connection open so the In-Memory SQLite database doesn't vanish when the connection get's closed.
The unit test with the connection string I was trying is...
public class SQLite_InMemory_SimpleRepositoryTests
{
public class Job
{
public Guid JobId { get; set; }
public string JobName { get; set; }
}
[Fact]
public void SQLite_InMemory_SimpleRepo_CanStayOpen()
{
IDataProvider provider = ProviderFactory.GetProvider("Data Source=:memory:;Version=3;New=True;Pooling=True;Max Pool Size=1;", "System.Data.SQLite");
IRepository repository = new SimpleRepository(provider, SimpleRepositoryOptions.RunMigrations);
for (int i = 0; i < 10000; i++)
{
var job = new Job {JobId = Guid.NewGuid(), JobName = "Job_"+i};
repository.Add(job);
}
}
}
I tried setting the "Shared Connection" on the IDataProvider, but the connection still seemed to close.
If not, I'll update the SubSonic source, and submit the changes.
Thanks!
Interesting - no there's no way that I can think of to do this other than maybe creating a static IDataProvider but even then we close off the connection for doing things like executing scalar's etc.
I spose you could create such a thing by implementing the IDataProvider then setting things up as you need - all the execution goes through it. But this is making me wonder if we explicitly shut things down in the calling code - which would be bad design on my part... hmmm.\
Would love to have this feature...

3 Tier Architecture - In need of an example

Presently I am working using single tier architecture. Now I am wanting to learn how to write code using 3 tier architecture. Please can you provide me with a simple example?
Wikipedia have a nice explanation: Multitier architecture:
'Three-tier' is a client-server architecture in which the user interface, functional process logic ("business rules"), computer data storage and data access are developed and maintained as independent modules, most often on separate platforms.
Web development usage
In the web development field, three-tier is often used to refer to websites, commonly electronic commerce websites, which are built using three tiers:
A front end web server serving static content, and potentially some cached dynamic content.
A middle dynamic content processing and generation level application server, for example Java EE, ASP.net, PHP platform.
A back-end database, comprising both data sets and the database management system or RDBMS software that manages and provides access to the data.
This is what I have in my project. More than just a traditional 3-tier architecture.
1.) Application.Infrastructure
Base classes for all businessobjects, busines object collection, data-access classes and my custom attributes and utilities as extension methods, Generic validation framework. This determines overall behavior organization of my final .net application.
2.) Application.DataModel
Typed Dataset for the Database.
TableAdapters extended to incorporate Transactions and other features I may need.
3.) Application.DataAccess
Data access classes.
Actual place where Database actions are queried using underlying Typed Dataset.
4.) Application.DomainObjects
Business objects and Business object collections.
Enums.
5.) Application.BusinessLayer
Provides manager classes accessible from Presentation layer.
HttpHandlers.
My own Page base class.
More things go here..
6.) Application.WebClient or Application.WindowsClient
My presentation layer
Takes references from Application.BusinessLayer and Application.BusinessObjects.
Application.BusinessObjects are used across the application and they travel across all layers whenever neeeded [except Application.DataModel and Application.Infrastructure]
All my queries are defined only Application.DataModel.
Application.DataAccess returns or takes Business objects as part of any data-access operation. Business objects are created with the help of reflection attributes. Each business object is marked with an attribute mapping to target table in database and properties within the business object are marked with attributes mapping to target coloumn in respective data-base table.
My validation framework lets me validate each field with the help of designated ValidationAttribute.
My framrwork heavily uses Attributes to automate most of the tedious tasks like mapping and validation. I can also new feature as new aspect in the framework.
A sample business object would look like this in my application.
User.cs
[TableMapping("Users")]
public class User : EntityBase
{
#region Constructor(s)
public AppUser()
{
BookCollection = new BookCollection();
}
#endregion
#region Properties
#region Default Properties - Direct Field Mapping using DataFieldMappingAttribute
private System.Int32 _UserId;
private System.String _FirstName;
private System.String _LastName;
private System.String _UserName;
private System.Boolean _IsActive;
[DataFieldMapping("UserID")]
[DataObjectFieldAttribute(true, true, false)]
[NotNullOrEmpty(Message = "UserID From Users Table Is Required.")]
public override int Id
{
get
{
return _UserId;
}
set
{
_UserId = value;
}
}
[DataFieldMapping("UserName")]
[Searchable]
[NotNullOrEmpty(Message = "Username Is Required.")]
public string UserName
{
get
{
return _UserName;
}
set
{
_UserName = value;
}
}
[DataFieldMapping("FirstName")]
[Searchable]
public string FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
[DataFieldMapping("LastName")]
[Searchable]
public string LastName
{
get
{
return _LastName;
}
set
{
_LastName = value;
}
}
[DataFieldMapping("IsActive")]
public bool IsActive
{
get
{
return _IsActive;
}
set
{
_IsActive = value;
}
}
#region One-To-Many Mappings
public BookCollection Books { get; set; }
#endregion
#region Derived Properties
public string FullName { get { return this.FirstName + " " + this.LastName; } }
#endregion
#endregion
public override bool Validate()
{
bool baseValid = base.Validate();
bool localValid = Books.Validate();
return baseValid && localValid;
}
}
BookCollection.cs
/// <summary>
/// The BookCollection class is designed to work with lists of instances of Book.
/// </summary>
public class BookCollection : EntityCollectionBase<Book>
{
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection()
{
}
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection (IList<Book> initialList)
: base(initialList)
{
}
}
By "tier" do you mean a "layer" in your software stack? The word "tier" is better used to describe the physical components of your system. If you are using ASP.NET, you probably already have a "3 tiered" system -
Browser displaying web pages
IIS Server hosting your app
Database Server with your database
But you are possibly putting all of your code into a single software "layer" - specifically, the code behind file of your aspx pages. You want to move from a single layer to a 3 layer approach. The classic "3 layer" software architecture consists of the following -
Presentation Layer
Business Logic Layer (BLL)
Data Access Layer (DAL)
(source: asp.net)
For a typical ASP.NET app, you might apply this as follows. First, you create a LINQ2SQL file (.dbml) containing the objects for your database access. This is your Data Access Layer (DAL).
Next you might create a DLL to contain your Business Logic Layer (BLL). This layer will access the database via the DAL, manipulate it as required, and then expose it via a simple interface. For example, if your application displays a client list, your BLL might have a public function called GetClientList() which returned a list of clients.
Finally you would set up your code behind files to instantiate the BLL and wire it up to the interface components. This is your Presentation Layer. For example, it might take the data returned from your GetClientList() function and bind it to a data grid on the web form. The idea is to have the presentation layer as thin as possible.
This seems a little long-winded to describe, but it's pretty straight-forward once you have done it a couple of times. You will find that separating out your application like this will make it much easier to maintain, as the separation of concerns leads to cleaner code. You will also find it much easier to upgrade or even replace your presentation layer, as it contains very little smarts. Finally, you will get to a point where you have a number of very useful BLL libraries that you can easily consume in new applications, greatly improving productivity.
Presentation layer: put everything that is related to user interface. (What the user sees)
Business layer: everything that is related to the logic of the application (How is the information coming from presentation layer treated)
Data layer: provide an abstraction of the underlying data source(s) (Where and how the information coming from/going to business layer is stored)
Each layer should know as less as possible about the other and it should be a top down approach:
the data layer should know nothing about business and presentation
business layer should know about data but not about presentation
presentation should know about business but not about data
Simple example:
Website:
Presentation: all the graphical things, fields where user inserts data, menus, pictures, etc.
Business: all constraints about the data (unique name, name without symbols, valid date, etc), methods for manipulating business objects (create new user, add new order, etc)
Data: Methods that access the underlying database.
3-tier architecture can have different meanings depending on context. Generally it means that responsibilities in the application are divided between different tiers. Typically, 3-tier refers to :
presentation tier" (actual user interface)
logic tier (application/business logic)
data tier (database, data storage)
The details vary by application.
Wikipedia, as usual, has a nice overview: http://en.wikipedia.org/wiki/Multitier_architecture
A simple example would be a typical business app:
presentation: browser, or fat client
logic tier: business logic, typically in an application server (based on J2EE, ASP.NET or whatever)
data tier: a database, typically a RDBMS such as MySQL or Oracle
A 3-tier architecture usually has the following components:
Client Browser
Web server hosting the ASP.NET application
Some backend storage such as database that is being accessed by the ASP.NET application
So to answer your question on how to write code for a 3-tier architecture, you develop an ASP.NET application that communicates with a data storage.
A good tutorial, with complete source control download of a well written tiered application would be here:
http://nerddinnerbook.s3.amazonaws.com/Intro.htm
This isn't a tutorial about tiered architecture, but it's a well written app and gives some insight into why you might consider this architecture.
Additionally, as has only been briefly touched on above, this is about keeping your logic/storage/presentation code separate, so if you have to change one of them (e.g change from asp.net front end to a desktop application), it's not so hard to do.
Three-tier (layer) is a client-server architecture in which the user interface, business process (business rules) and data storage and data access are developed and maintained as independent modules or most often on separate platforms.
Basically, there are 3 layers:
tier 1 (presentation tier, GUI tier)
tier 2 (business objects, business logic tier)
tier 3 (data access tier). These tiers can be developed and tested separately.
What is the need for dividing the code in 3-tiers? Separation of the user interface from business logic and database access has many advantages. Some of the advantages are as follows:
Reusability of the business logic component results in quick
development. Let's say we have a module that handles adding, updating,
deleting and finding customers in the system. As this component is
developed and tested, we can use it in any other project that might
involve maintaining customers.
Transformation of the system is easy. Since the business logic is
separate from the data access layer, changing the data access layer
won’t affect the business logic module much. Let's say if we are
moving from SQL Server data storage to Oracle there shouldn’t be any
changes required in the business layer component and in the GUI
component.
Change management of the system is easy. Let's say if there is a minor
change in the business logic, we don’t have to install the entire
system in individual user’s PCs. E.g. if GST (TAX) is changed from 10%
to 15% we only need to update the business logic component without
affecting the users and without any downtime.
Having separate functionality servers allows for parallel development
of individual tiers by application specialists.
Provides more flexible resource allocation. Can reduce the network
traffic by having the functionality servers strip data to the precise
structure needed before sending it to the clients.
connection class
-----------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web .UI.WebControls ;
/// <summary>
/// Summary description for conn
/// </summary>
namespace apm_conn
{
public class conn
{
public SqlConnection getcon()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["connect"].ConnectionString );
if (con.State == ConnectionState.Closed)
{
con.Open();
}
return con;
}
#region execute command
public string Executecommand(SqlParameter []sqlparm,string sp)
{
string r_val = "";
try
{
SqlConnection con = new SqlConnection();
con = getcon();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = sp;
cmd.CommandType = CommandType.StoredProcedure;
foreach (SqlParameter loopvar_parm in sqlparm)
{
cmd.Parameters.Add(loopvar_parm);
}
cmd.Parameters.Add("#Var_Output", SqlDbType.VarChar, 20).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
r_val = (string)cmd.Parameters["#Var_Output"].Value;
con.Close();
}
catch { }
return r_val;
}
#endregion
#region Execute Dataset
public DataSet ExeccuteDataset(SqlParameter[] sqlParm, string sp)
{
DataSet ds = new DataSet();
try
{
SqlConnection con = new SqlConnection();
con = getConn();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = sp;
foreach (SqlParameter LoopVar_param in sqlParm)
{
cmd.Parameters.Add(LoopVar_param);
}
cmd.ExecuteNonQuery();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
}
catch
{ }
return ds;
}
#endregion
#region grid
public void Bindgrid(DataSet ds,GridView g)
{
try
{
g.DataSource = ds.Tables[0];
g.DataBind();
}
catch { }
}
#endregion
#region Dropdownlist
public void Binddropdown(DropDownList dl,DataSet ds,string text,string value)
{
try
{
dl.DataSource = ds.Tables[0];
dl.DataTextField = text;
dl.DataValueField = value;
dl.DataBind();
}
catch
{}
}
#endregion
public conn()
{
//
// TODO: Add constructor logic here
//
}
}
}
dal
---------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using apm_conn;
using System.Data.SqlClient;
using apm_ent;
/// <summary>
/// Summary description for Class1
/// </summary>
namespace apm_dal
{
public class dal
{
conn ob_conn = new conn();
public dal()
{
//
// TODO: Add constructor logic here
//
}
public string insert(ent obj_ent)
{
SqlParameter[] sqlparm =
{
new SqlParameter ("#Var_Action",obj_ent.Var_Action),
new SqlParameter ("#Int_Id",obj_ent.Int_Id ),
new SqlParameter ("#Var_Product",obj_ent.Var_Product ),
new SqlParameter ("#Dc_Price",obj_ent.Var_Price ),
new SqlParameter ("#Int_Stat",obj_ent.Int_Stat ),
};
return ob_conn.Executecommand(sqlparm, "Proc_product");
}
public string ins(ent obj_ent)
{
SqlParameter[] parm =
{
new SqlParameter ("#Var_Action",obj_ent .Var_Action),
new SqlParameter ("#Int_Id",obj_ent .Int_Id),
};
return ob_conn.Executecommand(parm, "Proc_product");
}
}
}
bal
-------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using apm_ent;
using apm_dal;
/// <summary>
/// Summary description for bal
/// </summary>
namespace apm_Bal
{
public class bal
{
dal ob_dal = new dal();
string r_val = "";
public bal()
{
//
// TODO: Add constructor logic here
//
}
public string insert(ent obj_ent)
{
return ob_dal.insert(obj_ent);
}
}
}
Ent
------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// Summary description for ent
/// </summary>
namespace apm_ent
{
public class ent
{
public ent()
{
//
// TODO: Add constructor logic here
//
}
#region Ent
public int Int_Id { get; set; }
public string Var_Action { get; set; }
public string Var_Product { get; set; }
public decimal Var_Price { get; set; }
public int Int_Stat { get; set; }
#endregion
}
}
page code
--------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using apm_conn;
using apm_ent;
using apm_Bal;
using apm_conn;
public partial class _Default : System.Web.UI.Page
{
conn obj_conn = new conn();
ent obj_ent = new ent();
bal obj_bal = new bal();
string r_val = "";
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnsub_Click(object sender, EventArgs e)
{
obj_ent.Var_Action = "INS";
obj_ent.Var_Product = txtproduct.Text;
obj_ent.Var_Price = Convert.ToDecimal (txtprice.Text);
r_val = obj_bal.insert(obj_ent);
if (r_val == "1")
{
Response.Write("<script>alert('Inserted Sucessfully')</script>");
}
}
}

How to Track Queries on a Linq-to-sql DataContext

In the herding code podcast 14 someone mentions that stackoverflow displayed the queries that were executed during a request at the bottom of the page.
It sounds like an excellent idea to me. Every time a page loads I want to know what sql statements are executed and also a count of the total number of DB round trips.
Does anyone have a neat solution to this problem?
What do you think is an acceptable number of queries? I was thinking that during development I might have my application throw an exception if more than 30 queries are required to render a page.
EDIT: I think I must not have explained my question clearly. During a HTTP request a web application might execute a dozen or more sql statements. I want to have those statements appended to the bottom of the page, along with a count of the number of statements.
HERE IS MY SOLUTION:
I created a TextWriter class that the DataContext can write to:
public class Logger : StreamWriter
{
public string Buffer { get; private set; }
public int QueryCounter { get; private set; }
public Logger() : base(new MemoryStream())
{}
public override void Write(string value)
{
Buffer += value + "<br/><br/>";
if (!value.StartsWith("--")) QueryCounter++;
}
public override void WriteLine(string value)
{
Buffer += value + "<br/><br/>";
if (!value.StartsWith("--")) QueryCounter++;
}
}
In the DataContext's constructor I setup the logger:
public HeraldDBDataContext()
: base(ConfigurationManager.ConnectionStrings["Herald"].ConnectionString, mappingSource)
{
Log = new Logger();
}
Finally, I use the Application_OnEndRequest event to add the results to the bottom of the page:
protected void Application_OnEndRequest(Object sender, EventArgs e)
{
Logger logger = DataContextFactory.Context.Log as Logger;
Response.Write("Query count : " + logger.QueryCounter);
Response.Write("<br/><br/>");
Response.Write(logger.Buffer);
}
If you put .ToString() to a var query variable you get the sql. You can laso use this in Debug en VS2008. Debug Visualizer
ex:
var query = from p in db.Table
select p;
MessageBox.SHow(query.ToString());
System.IO.StreamWriter httpResponseStreamWriter =
new StreamWriter(HttpContext.Current.Response.OutputStream);
dataContext.Log = httpResponseStreamWriter;
Stick that in your page and you'll get the SQL dumped out on the page. Obviously, I'd wrap that in a little method that you can enable/disable.
I have a post on my blog that covers sending to log files, memory, the debug window or multiple writers.
From Linq in Action
Microsoft has a Query Visualizer tool that can be downloaded separetly from VS 2008. it is at http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx

Resources