Salut les Gars !
I am back with a little code I wrote today for my business. I had to create a little phone book.
The db I had to query was pretty complicated and I did not want to create all the stuff you need for an effective Linq ot Sql classes. Therefore, I decided to use a stored procedure who retrieve all the users (about 5000) with all the information I need. This application will be a one-shot application and his time life will be about 1 or 2 years. Also, the release date is very tight.
I am not going to teach you how to create one. All you need to know is the result of the query. My stored prod will return a row with the Email column, the city, the office address,…
Here, an example of a stored prod you might deal with :
SELECT uEmail, Offices.ofPostalCode , uTelExtension, uMobilePhone, uDefaultLang, Offices.ofTelephone, ofFax, rsName.value, rsCity.value as 'City', rsAdd.value as 'Address', rsAddSuite.value as 'Suite', (Select Resources.value FROM States join Resources ON Resources.rsID = States.rsStName AND Resources.loID = Users.uDefaultLang WHERE States.stID = Offices.stID) as 'State/Province', (Select Resources.value FROM Countries join Resources ON Resources.rsID = Countries.rsCnName AND Resources.loID = Users.uDefaultLang WHERE Countries.cnID = Offices.cnID) as 'Country' FROM Users join Offices ON Users.ofID = Offices.ofID join Resources AS rsName ON rsName.rsID = Offices.rsOfName AND rsName.loID = Users.uDefaultLang join Resources AS rsCity ON rsCity.rsID = Offices.rsOfCity AND rsCity.loID = Users.uDefaultLang join Resources AS rsAdd ON rsAdd.rsID = Offices.rsOfAddress AND rsAdd.loID = Users.uDefaultLang join Resources AS rsAddSuite ON rsAddSuite.rsID = Offices.rsOfAddressSuite AND rsAddSuite.loID = Users.uDefaultLang join States ON States.stID = Offices.stID join Countries ON Countries.cnID = Offices.cnID WHERE uTelExtension != ''
I know, there is no parameter in the stored prod but we could add some later (the language for example).
Create an Linq to Sql class to you solution or use one you already have. Open you Server Explorer, add a connection to the db you want simply drag and drop the stored procedure in the dbml.

So I added this in a SqlUserRepository class which I will use in my controller to retrieve data and filter it.
public IEnumerable<UserDB> getUserFromDb()
{
LinqToUsersDataContext db = new LinqToUsersDataContext();
var res = from Users in db.spUserGetUserDB()
select new UserDB()
{
Email = Users.uEmail,
Address = Users.Address,
City = Users.City,
Country = Users.Country,
StateProvince = Users.State_Province,
MobilePhone = Users.uMobilePhone,
ofTelephone = Users.ofTelephone,
Suite = Users.Suite,
TexExtension = Users.uTelExtension
};
return res.AsEnumerable();
}
For this example, I will create two filters, one which will filter by Email and the other which will filter by City Name. Note that we do not speak here about best design and performance. We want something quickly. I guess when you read the stored prod, you said “Oh what for a crap”, yes I know but it was an old db with bad design and I must deal with…
Back to our Filters, the magic word here is “this”. You create a static class with an Ubiquitous Language (DDD style, traduction explicit name) and you create some static methods. In this example, it is “this IQueryable<UserDB>” and if you play with an object of that type, the intellisense will detect automatically and will show it to you (Like we saw in a previous post, here).
public static class UserDBFilter
{
public static IQueryable<UserDB> LikeEmail(this IQueryable<UserDB> qry, string Email )
{
return from user in qry where user.Email.Contains(Email) select user;
}
public static IQueryable<UserDB> WithCity(this IQueryable<UserDB> qry, string City)
{
return from user in qry where user.City == City select user;
}
}
To test if everything works fine, I created a little integration test.
[TestMethod]
public void GetRetrieveUserFromDbwithparam()
{
string email;
string city;
email = "pierre@dervalp.com";
city = "Tokyo";
var res = _service.getUserFromDb().AsQueryable();
if (!string.IsNullOrEmpty(email))
res = res.LikeEmail(email);
if (!string.IsNullOrEmpty(city))
res = res.WithCity(city);
Assert.IsNull(res);
}
It tried to put the string email to null, after the sting city to null, after both. In every case I receive what I wanted to have.
We create a basic controller and add a function ListUsers(). Per default, we render all the users (for example).
private readonly SqlRepositoryService _dbService;
//CTOR (instantiate the service you need)
public MergeController()
{
_dbService = new SqlRepositoryService();
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult ListUsers()
{
// PagedList<UserDB> userlist = new PagedList<UserDB>(_dbService.getUserFromDb().ToList(),0, 5);
IList<UserDB> userlist = new List<UserDB>(_dbService.getUserFromDb());
return View(userlist);
}
Right-click on ListUsers() and create a strong typely-type view List. If you run the application, you will receive all the user in a List.
I cannot show you the result (private information inside).
I add my little form on the view :
<% using (Html.BeginForm("List","Merge"))
{%>
<label for="Email">Email:</label>
<%=Html.TextBox("Email")%>
<label for="City">City:</label>
<%=Html.TextBox("City")%>
<input id="searchform" type="submit" value="Search" />
<%}%>
We add a method for the post :
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult List(FormCollection forms)
{
string Email = Request.Form["Email"];
string City = Request.Form["City"];
var res = _dbService.getUserFromDb().AsQueryable();
if (!string.IsNullOrEmpty(Email))
res = res.LikeEmail(Email);
if (!string.IsNullOrEmpty(City))
res = res.WithCity(City);
return View(res);
}
Run the application and make a search with an email and it works !
Of course, the design of this little application could be discussed but I make a phone book in 10 minutes and I am sure that after one day of refactoring, I could put this application in a production status (Add pagination, add improvemnts for query, some javascript,…).
So, I am waiting for your feedback…
6 Responses to ASP.NET MVC C# Linq to Stored procedure with Dynamic Query (a quick phone book, piece of Cake !)
Nisar Khan
July 1st, 2009 at 9:19 am
i’m on the same boat as you are means the bad db design and also the complex sp…. and i like your post very much and wondeing if you can provide a download link of what you have done?
thanks.
Nisar Khan
July 1st, 2009 at 1:41 pm
great job man… if you have modified like adding pagination, add improvemnts for query, some javascript,…) please share with us.
thanks a lot for putting on the web.
dsm
July 1st, 2009 at 6:36 pm
where you closing the datacontext (LinqToUsersDataContext ) ?
sanfra
July 31st, 2009 at 7:55 am
Hello and congratulations for all this, I have to implement a dynamic query and I have three related tables between loro.Ho fre tried your example, but gives me the error value can not be null.
Parameter name: source
this is what I implement as far as the method that calls the stored public IEnumerable GetBollettinoBySearch (DateTime date, DateTime dataf)
(
var res = from b in comunedb.Search (date, dataf)
select new
(
b.Cognome,
b.Nome,
b.Cf,
b.Cap,
b.Provincia,
b.Via,
b.Telefono,
b.Comune,
b.Data_inserimento,
b.Data_Versamento,
b.Importo,
b.IdOperatore,
b.Note,
b.Nr_CC,
b.Causale
);
return res as IEnumerable;
)
You have an idea why?
Thanks and congratulations again
asp.net books
August 16th, 2009 at 12:33 pm
This was avery interesting way to acheive what you wanted, quite a good method for a small scale application
MINESH GHIMIRE
August 31st, 2009 at 2:55 am
SIMPLE BUT GOOD EXAMPLE FOR THE BEGINNERS