Monday, December 29, 2008

Select DISTINCT on DataTable

In a project I'm doing I needed to basically do a DISTINCT on a couple fields in a DataTable that I had used earlier in code. Did some Google searching and came up with this MS KB on the subject. I was hoping to find it in the Framework, but hey, writing a little extra code never hurt anyway. Looking over the code though I found that I just didn't really like it. Biggest reason being it only took one field. I wanted to be able to pass in n number of fields, so I rewrote it and did a little tweaking to it. Here's what I came up with in both VB and C#
VB
Public Shared Function SelectDistinct(ByVal SourceTable As DataTable, ByVal ParamArray FieldNames() As String) As DataTable Dim lastValues() As Object Dim newTable As DataTable If FieldNames Is Nothing OrElse FieldNames.Length = 0 Then Throw New ArgumentNullException("FieldNames") End If lastValues = New Object(FieldNames.Length - 1) {} newTable = New DataTable For Each field As String In FieldNames newTable.Columns.Add(field, SourceTable.Columns(field).DataType) Next For Each Row As DataRow In SourceTable.Select("", String.Join(", ", FieldNames)) If Not fieldValuesAreEqual(lastValues, Row, FieldNames) Then newTable.Rows.Add(createRowClone(Row, newTable.NewRow(), FieldNames)) setLastValues(lastValues, Row, FieldNames) End If Next Return newTableEnd Function
Private Shared Function fieldValuesAreEqual(ByVal lastValues() As Object, ByVal currentRow As DataRow, ByVal fieldNames() As String) As Boolean Dim areEqual As Boolean = True For i As Integer = 0 To fieldNames.Length - 1 If lastValues(i) Is Nothing OrElse Not lastValues(i).Equals(currentRow(fieldNames(i))) Then areEqual = False Exit For End If Next Return areEqualEnd Function
Private Shared Function createRowClone(ByVal sourceRow As DataRow, ByVal newRow As DataRow, ByVal fieldNames() As String) As DataRow For Each field As String In fieldNames newRow(field) = sourceRow(field) Next Return newRowEnd Function
Private Shared Sub setLastValues(ByVal lastValues() As Object, ByVal sourceRow As DataRow, ByVal fieldNames() As String) For i As Integer = 0 To fieldNames.Length - 1 lastValues(i) = sourceRow(fieldNames(i)) NextEnd Sub
C#
private static DataTable SelectDistinct(DataTable SourceTable, params string[] FieldNames){ object[] lastValues; DataTable newTable; DataRow[] orderedRows; if (FieldNames == null FieldNames.Length == 0) throw new ArgumentNullException("FieldNames"); lastValues = new object[FieldNames.Length]; newTable = new DataTable(); foreach (string fieldName in FieldNames) newTable.Columns.Add(fieldName, SourceTable.Columns[fieldName].DataType); orderedRows = SourceTable.Select("", string.Join(", ", FieldNames)); foreach (DataRow row in orderedRows) { if (!fieldValuesAreEqual(lastValues, row, FieldNames)) { newTable.Rows.Add(createRowClone(row, newTable.NewRow(), FieldNames)); setLastValues(lastValues, row, FieldNames); } } return newTable;}
private static bool fieldValuesAreEqual(object[] lastValues, DataRow currentRow, string[] fieldNames){ bool areEqual = true; for (int i = 0; i < fieldNames.Length; i++) { if (lastValues[i] == null !lastValues[i].Equals(currentRow[fieldNames[i]])) { areEqual = false; break; } } return areEqual;}
private static DataRow createRowClone(DataRow sourceRow, DataRow newRow, string[] fieldNames){ foreach (string field in fieldNames) newRow[field] = sourceRow[field]; return newRow;}
private static void setLastValues(object[] lastValues, DataRow sourceRow, string[] fieldNames){ for (int i = 0; i < fieldNames.Length; i++) lastValues[i] = sourceRow[fieldNames[i]];}
I thought I'd also point out a downfall from the KB that I corrected in my example. The beginning of the For Each calls SourceTable.Select("", FieldName)) in it. This can hinder performance a bit in certain situations, because in C# that statement will be evaulated for every loop iteration. You can see in the C# code that I have I actually call the Select Method and store the results in a variable and use it in the loop instead. One other interesting thing to note about the different between the VB and the C# code is that I DID NOT put the results of the Select Method in a variable in the VB code even though I did in the C# code. This is because VB works differently in that the actual For Each loop only evaluates the first iteration of the loop, which is nice and saves and extra line or two of code. Another thing that's different between the two (sorry, I think the differences between the two are interesting) is that to instantiate a new Object Array in the lastValues variable in VB you have to put {} after it, and in C# you don't have to. This is because since VB uses the same characters for Methods vs. Indexers, the compiler wouldn't be able to tell the difference between calling a constructor with one parameter vs. creating a new array, so it's necessary. In C# it knows since you're using the indexer characters, you mean a new array, not a new object in this case. That said, if you like using the VB Functions, you could also just call ReDim lastValues(FieldNames.Length), but I tend to stay away from those since I do a lot of code in both VB and C#.

Limit the string value to given number of characters

Limit the string value to given number of characters but dont break the word
Function TrimString(ByVal strString, ByVal intLength) Dim aryString As String() strString = Replace(strString, vbCrLf, "") If Len(strString) > intLength Then strString = Left(strString, intLength) aryString = Split(strString, " ") strString = "" For a As Integer = 0 To UBound(aryString) - 1 strString = strString & " " & aryString(a) Next strString = Trim(strString) strString = strString & "..." End If TrimString = strString End Function

Remove HTML from your string

Pass the strng value to below mentioned function to scrab out HTML

Public Shared Function StripHtml(ByVal html As String, ByVal allowHarmlessTags As Boolean) As String If html Is Nothing OrElse html = String.Empty Then Return String.Empty End If
If allowHarmlessTags Then Return System.Text.RegularExpressions.Regex.Replace(html, "", String.Empty) End If
Return System.Text.RegularExpressions.Regex.Replace(html, "<[^>]*>", String.Empty) End Function

Thursday, June 5, 2008

How do I use a robots.txt file to control access to my site?

A robots.txt file provides restrictions to search engine robots (known as "bots") that crawl the web. These bots are automated, and before they access pages of a site, they check to see if a robots.txt file exists that prevents them from accessing certain pages.
You need a robots.txt file only if your site includes content that you don't want search engines to index. If you want search engines to index everything in your site, you don't need a robots.txt file (not even an empty one).
For more information go to below mentioned link
http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=40360

Thursday, February 21, 2008

Storing the password in secure form and reading it back

  • Create the table which have fields UserName and Passwords and set Password field Varbinary

CREATE TABLE [dbo].[User] ([ID] [int] IDENTITY (1, 1) NOT NULL ,[UserName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,[Password] [varbinary] (255) NULL ,) ON [PRIMARY]GO

  • Now store UserName and Password by using new method pwdencrypt().

INSERT INTO UserEncrycptTable(UserName,[Password]) VALUES ( 'Firoz',pwdencrypt('PasswordFiroz'));

  • When we execute the above query and open the table you will notice that password is not in plain text.
  • Now we will retrive this password usin method using the method pwdencrypt().

DECLARE @varPassword varbinary(255)SELECT @varPassword = [Password] FROM UserEncrycptTable where UserName = 'Firoz'

DECLARE @chkPassword varchar(255)

SELECT @chkPassword = 'PasswordFiroz'

PRINT pwdcompare(@chkPassword, @varPassword, 0);

Wednesday, February 20, 2008

Tips for increase performance of SQL database

  1. Create a primary key on each table you create and unless you are really knowledgeable enough to figure out a better plan, make it the clustered index (note that if you set the primary key in Enterprise Manager it will cluster it by default).
  2. Create an index on any column that is a foreign key. If you know it will be unique, set the flag to force the index to be unique.
  3. Don’t index anything else (yet).
  4. Unless you need a different behaviour, always owner qualify your objects when you reference them in TSQL. Use dbo.sysdatabases instead of just sysdatabases.
  5. Use set nocount on at the top of each stored procedure (and set nocount off) at the bottom.
  6. Think hard about locking. If you’re not writing banking software, would it matter that you take a chance on a dirty read? You can use the NOLOCK hint, but it’s often easier to use SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED at the top of the procedure, then reset to READ COMMITTED at the bottom.
  7. Use transactions when appropriate, but allow zero user interaction while the transaction is in progress. I try to do all my transactions inside a stored procedure.
  8. Avoid temp tables as much as you can, but if you need a temp table, create it explicitly using Create Table #temp.
  9. Avoid NOT IN, instead use a left outer join - even though it’s often easier to visualize the NOT IN.
  10. If you insist on using dynamic sql (executing a concatenated string), use named parameters and sp_executesql (rather than EXEC) so you have a chance of reusing the query plan. While it’s simplistic to say that stored procedures are always the right answer, it’s also close enough that you won’t go wrong using them.
  11. Get in the habit of profiling your code before and after each change. While you should keep in mind the depth of the change, if you see more than a 10-15% increase in CPU, Reads, or Writes it probably needs to be reviewed.
  12. Look for every possible way to reduce the number of round trips to the server. Returning multiple resultsets is one way to do this.
  13. Avoid index and join hints.
  14. When you’re done coding, set Profiler to monitor statements from your machine only, then run through the application from start to finish once. Take a look at the number of reads and writes, and the number of calls to the server. See anything that looks unusual? It’s not uncommon to see calls to procedures that are no longer used, or to see duplicate calls. Impress your DBA by asking him to review those results with you.

Monday, February 11, 2008

How To Retain Password Field Data during round trips to server

Preserve Password Field Data
When Use the password text box on the ASP.NET page and want to preserve the value of the password field during round trips to server; Use that line of code in he block of code through which server roun trip happen

txtPassword.Attributes.Add("value", txtPassword.Text.ToString());

Use "App_Offline.htm" feature while updating a web site

Use "App_Offline.htm" feature while updating a web site

"App_Offline.htm" feature provides a super convenient way to bring down an ASP.NET application while you updating a lot of content or making big changes to the site where you want to ensure that no users are accessing the application until all changes are done. The way app_offline.htm works is that you place this file in the root of the application. When ASP.NET sees it, it will shut-down the app-domain for the application and instead send back the contents of the app_offline.htm file in response to all new dynamic requests for the application. When you are done updating the site, just delete the file and it will come back online.