Jon's Blog

.NET Development & More

How to Use FreeTextTable

clock September 1, 2010 10:41 by author Jon

The FreeTextTable function in SQL Server is very useful when you need to search a column for words, phrases, etc. FreeTextTable will return a table that you can join on.  It also returns the Rank of the matches so you can order the most relevant matches at the top.

In the example below I am searching the Keywords column of the MyTable table using the @Keywords passed into the stored procedure.  I am then ordering them by Rank so the highest matches show up first.

CREATE PROCEDURE [dbo].[FreeTextSample]
    @Keywords [varchar](1000) = ''
WITH EXECUTE AS CALLER
AS
BEGIN
    SET NOCOUNT ON;

    SELECT myTable.MyPrimaryKeyID,
        myTable.Title,
        myTable.Description
  FROM MyTable myTable(nolock) INNER JOIN FreeTextTable(dbo.MyTable, Keywords, @Keywords) AS searchTable ON myTable.MyPrimaryKeyID = searchTable.[KEY] ORDER By searchTable.[RANK] DESC END GO

 

One thing to note is that LINQ does not contain an equivalent keyword for FreeTextTable.  So what I did was to create a new method on my DataContext that returns the results of the stored procedure.  See my post here for further details on how to do this.



LinqDataSource: Efficient Custom Paging with LINQ

clock March 26, 2010 16:40 by author Jon

Creating a GridView (or other data control) with efficient paging is very easy with LINQ.  You can thank the Take and Skip operators for this; they allow you to only pull back the records you need.  In the simple example below we are using a LinqDataSource and handling its onselecting method to create our LINQ query and do our paging.  Set AutoPage to false since we are writing code to handle paging ourselves.  Also the PageSize property of the GridView control is being populated from a constant in the code-behind class.

ASPX:

<asp:LinqDataSource ID="linqDS" runat="server" AutoPage="false" 
    ContextTypeName="Namespace.MyDataContext" 
    onselecting="linqDS_Selecting" />
        
<asp:GridView ID="myGV" runat="server" DataSourceID="linqDS"
    AllowPaging="true" PageSize="<%# PAGE_SIZE %>"
    AutoGenerateColumns="false">
    <Columns>
        <!--Removed for simplicity -->
    </Columns>
</asp:GridView>

 

Code-behind:

// Const declared at top of code-behind
public const int PAGE_SIZE = 100;

protected void linqDS_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
    // LINQ query
    var query = from c in myDC.Class
                select c;
    
    // Set the total count     
    // so GridView knows how many pages to create    
    e.Arguments.TotalRowCount = query.Count();

    // Get only the rows we need for the page requested
    query = query.Skip(myGV.PageIndex * PAGE_SIZE).Take(PAGE_SIZE);

    e.Result = query;
}

 



LINQ: Mapping to an Enumerated Type in the LINQ Designer

clock February 2, 2010 16:02 by author Jon

Below is the syntax you can use in the Properties window of the LINQ Designer to map to an enum.  Set this under the Type property and use the fully qualified name of your enum.

Example: global::MyClassLibrary.MyStuff.MyClassName

Screenshot:



LINQ Advanced Search

clock September 16, 2009 14:55 by author Jon

When creating an advanced search you often need to dynamically create the Where statments in your SQL.  Here is an easy way to do this in LINQ.  In the example below orderID, lastName, firstName, shipped are all values retrieved from controls on the page.

var query = from orders in dataContext.MyOrdersTable
select orders;

if (orderID.HasValue)
{
query = query.Where(order => order.OrderID == orderID);
}
if (!string.IsNullOrEmpty(lastName))
{
query = query.Where(order => order.LastName == lastName);
}
if (!string.IsNullOrEmpty(firstName))
{
query = query.Where(order => order.FirstName == firstName);
}
if (shipped.HasValue)
{
query = query.Where(order => order.Shipped == shipped);
}

myGridView.DataSouce = query;
myGridView.DataBind();


Visual Studio: Build failed due to validation errors in dbml file

clock May 28, 2009 11:23 by author Jon

Today, while attempting to build a class library on our build box I received the following error in Visual Studio 2008:

"Build failed due to validation errors in [FileName].dbml.  Open the file and resolve the issues in the Error List, then try rebuilding the project."

However, when I went to the dbml file no errors were shown in the error list.  To resolve this I deleted the .designer.cs file associated with the dbml file.  Then in Solution Explorer I right-clicked on the dbml file and selected "Run Custom Tool."  This regenerated the .cs file and I was then able to see the error, which was the following:

"DBML1005: Mapping between DbType 'Date' and Type 'System.DateTime' in Column '[ColumnName]' of Type '[TypeName]' is not supported."

This was easy enough to fix.  The Server Data Type just needed to be changed to DateTime.  Strangely enough having just Date on my development machine did not break the build.

I believed the root of the problem may be that the version of Visual Studio on my development machine was 9.0.30729.1 SP and the build machine was 9.0.21022.8 RTM.



LINQ, Visual Studio, and Stored Procedure Mapping

clock May 13, 2009 01:43 by author Jon

So the other day while attempting to drag a stored procedure onto the LINQ Designer in Visual Studio I received the following error:

VS_LINQ_Proc_Error

The stored procedure was rather complex including a call to FREETEXT and for some reason the LINQ Designer would not accept it, so I manually mapped the stored procedure for the DataContext.  For future reference, here is some sample code:

public partial class MyDataContext
{
[Function(Name = "dbo.MyStoredProc")]
public ISingleResult<MyClass> MyProcName(
[Parameter(Name = "Parameter1")] int? parameter1,
[Parameter(Name = "Parameter2")] ProductCategory? parameter2,
[Parameter(Name = "Parameter3")] bool? parameter3)
{
IExecuteResult result = this.ExecuteMethodCall(this,
((MethodInfo)(MethodInfo.GetCurrentMethod())),
parameter1, parameter2, parameter3);

return ((ISingleResult<MyClass>)(result.ReturnValue));
}
}

 

Then you can call the stored procedure in code like so:

var results = myDC.MyProcName(parameter1, parameter2, parameter3);