Friday, March 26, 2010

Clearing the cache of a LINQ to SQL DataContext

I was having some problems with my test code in that the DataContext was returning the objects from the cache (even though it was querying the database) and this was skewing my integration tests. Through the use of Reflector I found that there actually is a method for clearing the cache, handily called ClearCache(). However, the method was internal and so could not be called directly from code.

Internal methods are, however, available through reflection (I'm a bit of a noob when it comes to reflection so there might be constraints on when they are and when they aren't but this works for me). In order to make it easy to clear the cache (for example, after saving but before retrieving the object from the database for checking it saved correctly) I have created an extension method to do the heavy lifting for me:


using System.Data.Linq;
using System.Reflection;

namespace MyNamespace
{
public static class Extensions
{
public static void ClearCache(this DataContext context)
{
const BindingFlags FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

var method = context.GetType().GetMethod("ClearCache", FLAGS);
method.Invoke(context, null);
}
}
}

//Usage example: (will NOT compile unless you change the Abc below and include it's namespace...)
public class Xyz
{
public void DoWork()
{//'Abc being whatever your particular SQL Metal-generated data context is called
AbcDataContext dataContext = new AbcDataContext("my optional connection string");

//do work...

//check out the 'Extension Method' magic! Now the our custom static method defined above can be called like this:
dataContext.ClearCache();

//do more work...
//take a break...
}
}

Saturday, March 20, 2010

Cannot add diagram to SQL Server 2005 DB: Database diagram support objects cannot be installed because this database does not have a valid owner.

I tried the above mentioned solution but still was not working and displaying the same error message - if you got the same error as me then just try the follwing lines in SQL Query:

EXEC sp_dbcmptlevel 'dbname', '90';

ALTER AUTHORIZATION ON DATABASE::dbname TO valid_login

Friday, March 19, 2010

Creating an Index

Syntax:
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ]
INDEX index_name ON table ( column1, ... )
[ WITH
[ PAD_INDEX ]
[ [ , ] FILLFACTOR = fillfactor1 ]
[ [ , ] IGNORE_DUP_KEY ]
[ [ , ] DROP_EXISTING ]
[ [ , ] STATISTICS_NORECOMPUTE ]
]
[ ON filegroup1 ]
UNIQUE
Indicates that a unique index is to be created.
CLUSTERED
Indicates that the index created is a clustered index.
NONCLUSTERED
Indicates that the index created is a nonclustered index.
index_name
Is the name of the index.
table
The name of the table on which the index is to be created.
column1, ...
The column or columns to which the index is to be applied.
PAD_INDEX
Specifies the space to be left open on each page (node) in the intermediate levels of the index. (This is useful only when FILLFACTOR is specified).
FILLFACTOR = fillfactor1
Specifies the fillfactor for the index as fillfactor1.
IGNORE_DUP_KEY
Controls what happens when an attempt is made to insert a duplicate key value into a column that is part of a unique clustered index.
DROP_EXISTING
Specifies that the named, preexisting clustered or nonclustered index should be dropped and the specified index rebuilt.
STATISTICS_NORECOMPUTE
Specifies that out-of-date index statistics are not automatically recomputed.
ON filegroup1
Creates the specified index on the given filegroup1.

An INDEX is created using the CREATE INDEX command.

Indexes may be:

    Clustered Index
    A clustered index actually stores the data records in physical order. Because a table can only be physically sorted in one order, a table can only define one clustered index. Having a clustered index also means that each time a record is inserted or deleted from a table, the table or at least parts of the table must be rewritten to maintain the physical order. Even an update to the key field of a clustered index causes the table to delete the 'old' record and then insert the 'new' record. Obviously maintaining the physical order of the records in a table can be quite expensive, especially if there are frequent updates to the table. However, if the table is used mostly for retrieval and reporting, the advantages of a clustered index come to the forefront.

    Clustered Indexes are suitable for:
    • Columns that contain a limited number of distinct values, such as a state column that contains only 50 distinct state codes.
    • Queries that return a range of values using operators such as BETWEEN, >, >=, <, and <=.
    • Columns that are accessed sequentially.
    • Queries that return large result sets.
    • Columns that are frequently accessed by queries involving join or GROUP BY clauses; typically these are foreign key columns.
    • OLTP-type applications where very fast single row lookup is required, typically by means of the primary key.

    Clustered indexes are not suitable for:
    • Columns that undergo frequent changes.
    • Covered queries. The more columns within the search key, the greater the chance for the data in the indexed column to change, resulting in additional I/O.

    Nonclustered Index
    A nonclustered index creates a separate 'internal' table that stores only the selected key values of the table in order. Each 'record' in this index contains the key value from one record in the table along with a pointer to either the data record itself or to a value in the clustered index. Because a nonclustered index does not require a physical sorting of the actual data, we can have as many nonclustered indexes associated with a single table as possible. The maximum limit is 249. For each insert, delete, and update performed, SQL updates the table.

    Nonclustered Indexes are suitable for:
    • Columns that contain a high number of distinct values, such as a combination of last name and first name (if a clustered index is used for other columns).
    • Queries that do not return large result sets.
    • Columns frequently involved in search conditions of a query (WHERE clause) that return exact matches.
    • Decision Support System applications for which joins and grouping are frequently required.
    • Covered queries.

    Note:
    • If CLUSTERED is not specified, a nonclustered index is created.
    • Index names must be unique within a table but need not be unique within a database.
    • Index names must follow the rules of identifiers.
    • Only the owner of the table can create indexes on the same table.

    Unique Index
    An index in which no two index values are the same is called a unique index. Sql Server checks for duplicate values when a unique index is created and each time data is subsequently added. If duplicate values exist, then an error message is generated. Unique indexes cannot be created on columns that already contain duplicate values.

    Fillfactor
    Fillfactor allows us to reserve free space on each page of the index. Fillfactor is a value from 1 through 100 that specifies the percentage of the index page to be left empty. If we do not use the fillfactor option and an index page fills up, SQL Server must take time to move half the index page to a new page to make room for new rows (Page Split). This operation is quite expensive. For update-intensive tables, a properly chosen fillfactor value yields better update performance than an improper fillfactor value. If no value is specified the default value for the fillfactor is 0.

    Examples

    Code:
    CREATE CLUSTERED INDEX Index_Name_Clstd ON Students(Name);
    Output:
    Index (Id = 2) is being rebuilt.
    Explanation:

    In the above example, we have built a clustered index, Index_Name_Clstd, on the 'Name' column of the 'Students' table.

    Language(s): MS SQL Server
    Code:
    CREATE NONCLUSTERED INDEX Index_Name_NonClstd ON Students(Name);
    Output:
    The command(s) completed successfully.
    Explanation:

    In the above example, we have built a nonclustered index, Index_Name_NonClstd, on the 'Name' column of the 'Students' table.

    Language(s): MS SQL Server
    Code:
    CREATE UNIQUE INDEX Index_Name_Unique ON Students (Name);
    Output:
    The command(s) completed successfully.
    Explanation:

    The above example creates a unique index, Index_Name_Unique, on the 'Name' column of the 'Students' table.

    Language(s): MS SQL Server
    Code:
    CREATE CLUSTERED
    INDEX Index_Name_Clstd_FF10 ON Students (Name)
    WITH FILLFACTOR=10;
    Output:
    Index (Id = 2) is being rebuilt.
    Index (Id = 3) is being rebuilt.
    Index (Id = 4) is being rebuilt.
    Index (Id = 2) is being rebuilt.
    Index (Id = 3) is being rebuilt.
    Index (Id = 4) is being rebuilt.
    Explanation:

    In the above example, we have built a new clustered index on the 'Name' field of the 'Students' table with a fillfactor of 10.

    Note: Drop any of the existing CLUSTERED INDEX using the DROP INDEX command.

    Language(s): MS SQL Server

Creating an Index

Syntax:
CREATE [ UNIQUE ] INDEX index ON table (field [ASC|DESC][, field [ASC|DESC], ...]) [WITH { PRIMARY | DISALLOW NULL | IGNORE NULL }]

The CREATE INDEX statement is used to index one or more fields in an existing table.

You can do this by giving the index a name, and by stating the table and field(s) to which the index will apply.

Examples

Code:
CREATE INDEX CustomerIndex ON Customers (Name);
Explanation:

This example creates a simple index on the Name field of the Customers table:

Language(s): MS SQL Server
Code:
CREATE INDEX CustomerIndex ON Customers (Name DESC, City);
Explanation:

By default, the values in a field are indexed in ascending order, but if you want to index them in descending order, you can add the reserved word DESC. You can also index more than one field simply by listing the fields within parentheses.

Language(s): MS SQL Server
Code:
CREATE UNIQUE INDEX CustomerIndex ON Customers (Name);
Explanation:

If you want to prohibit duplicate values in the indexed field or fields, you can use the reserved word UNIQUE.

Code:
CREATE UNIQUE INDEX CustomerIndex ON Customers (Name) WITH DISALLOW NULL;
Explanation:

The optional WITH clause allows you to enforce further data validation rules by using three options: With the DISALLOW NULL option you can prohibit NULL entries in the indexed field(s).

Language(s): MS SQL Server
Code:
CREATE UNIQUE INDEX CustomerIndex ON Customers (Name) WITH IGNORE NULL;
Explanation:

With the IGNORE NULL option you can exclude records with NULL values in the indexed field(s) from the index.

Language(s): MS SQL Server
Code:
CREATE UNIQUE INDEX OrderIndex ON OrderDetailsODBC (OrderID);
Explanation:

You can also use CREATE INDEX to create a pseudo index on a linked table in an ODBC data source, such as SQL SERVER Note however, that this will only work if the table does not already have an index. You do not need permission or access to the remote server to create the pseudo index, and the remote database will be unaware of and unaffected by the operation.

Note:
Microsoft warns, "The Microsoft Jet database engine doesn't support the use of any DDL statements with databases produced by any other database engine. Use the DAO (Data Access Objects) Create methods instead."

Language(s): MS SQL Server
Code:
CREATE INDEX CustomerIndex ON Customers (CustomerID) WITH PRIMARY;
Explanation:

While the PRIMARY option allows you to designate which indexed field or fields to be the primary key (since primary keys are always unique, there's no need to include the reserved word UNIQUE).

Note that you cannot use the reserved word PRIMARY to create an index on a table that already has a primary key.

Language(s): MS SQL Server

Friday, March 5, 2010

Get Table Primary Key Column(s)

Suppose the following MSSQL server problem. We know table name and need to get its Primary Key columns programmatically. In order to do it we will use the following system tables:


  • sysobjects - for all user objects.
  • sysindexkeys - for indexes and keys.
  • syscolumns - for tables columns.

The query will look like so:



SELECT [name]
FROM syscolumns
WHERE [id] IN (SELECT [id]
FROM sysobjects
WHERE [name] = @table_name)
AND colid IN (SELECT SIK.colid
FROM sysindexkeys SIK
JOIN sysobjects SO ON SIK.[id] = SO.[id]
WHERE SIK.indid = 1
AND SO.[name] = @table_name)