Can I manipulate the guts of a stored procedure with Entity Framework - asp.net

So far, I've been using classic ADO.NET model for database access. I have to tell you that I'm quite happy with it. But I have also been hearing much about Entity Framework recently so I thought I could give it a try. Actually the main reason which pushed me was the need to find a way to build the WHERE clause of my Stored Procedures. With the classic way I have to do either of the following:
Build the WHERE clause in the client side based on the user inputs and send it as a VARCHAR2 argument to the Stored Procedure, concatenate the WHERE clausewith the main part of the SQL and pass the whole string to EXECUTE_IMMEDIATE function. I personally hate to have to do so.
Inside the Stored Procedure construct lots and lots of SQL statements, which means I have to take all the possible combinations that WHERE clause might be composed of into account. This seems worse than the first case.
I know that EF has made it possible to use Stored Procedures as well. But will it be possible to build the WHERE part dynamically? Can EF rescue me somehow?

yes, you can use Dynamic queries in Linq.
Dynamic Query LIbrary
from scott gu example
var query = Northwind.Products.Where("Lastname LIKE "someValue%");
or some complex query
var query =
db.Customers.
Where("City = #0 and Orders.Count >= #1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
or from this answer Where clause dynamically.
var pr = PredicateBuilder.False<User>();
foreach (var name in names)
{
pr = pr.Or(x => x.Name == name && x.Username == name);
}
return query.AsExpandable().Where(pr);

Related

Call Stored Procedure from Entity Framework

I've done a lot of Googling re this subject, but can't seem to find any clear answer that works. This maybe because of the way the different EF versions has worked (or not) in the past.
I'm currently using Asp.Net 4.0 with EF 6.1. My model is database first. Additionally, I'm using my own UOW, repository pattern but this is just for information.
Firstly, the reason I want to call a stored procedure is because I need to incorporate a 'counter' into my table - put simply each time anyone visits a particular partner, I need to increment the counter. Of course, the main issue using EF is concurrency.
The articles I've read, tell me that EF isn't good at this type of update, however if this is now deemed easier to achieve in later EF versions, I'd be interested to hear more. Otherwise, I'm left with a native stored procedure - 2 options I guess
call from EF, and
call directly
Since I've been using primarily EF, my knowledge of SQL is fairly sparse, but I've created the following stored procedure:
ALTER PROCEDURE dbo.Popularity_Update
#TermID smallint
AS
SET NOCOUNT ON
DECLARE #Now date = SYSDATETIME()
BEGIN TRY
MERGE Popularity AS t
USING (SELECT #TermID AS TermID, #Now AS VisitDate) AS s ON t.TermID = s.TermID
AND t.VisitDate = s.VisitDate
WHEN MATCHED THEN
UPDATE
SET VisitCount += 1
WHEN NOT MATCHED BY TARGET THEN
INSERT (TermID, VisitDate, VisitCount)
VALUES (s.TermID, s.VisitDate, 1);
END TRY
BEGIN CATCH
END CATCH
That's were I get lost. I noticed within the EF designer that the stored procedure could be referenced, so I added the table to my model and then mapped the stored procedure.
But I also noticed that I can reference a stored procedure from code using the following code:
var name = new SqlParameter("TermID", typeof(short));
uow.Context.Database.ExecuteSqlCommand("Popularity_Update", name);
At the moment, I'm just confused and have lots of questions.
Can this be done in EF without a stored procedure?
Should it be done in EF without a stored procedure?
If I use a stored procedure - whats the best way to do this?
I'd appreciate any help/guidance available.
you cant use this in EF without a stored procedure.
the best way to do this is using the dynamically mapping.
Heres How I usually execute my stored procedures.
internal static Database Db = DatabaseFactory.CreateDatabase();//stated in my dataaccess layer
DbCommand dbCommand = Db.GetStoredProcCommand("Yourstoreprocturename");
Db.AddInParameter(dbCommand, "TermID", DbType.Int32, parameterofTermID);
Db.ExecuteNonQuery(dbCommand);
Took on board what the previous answers offered. Came up with this solution that caters specifically for the UOW/ Repository environment I'm working with.
public static void Increment(short termID)
{
termID.ThrowDefault("termID");
using (var uow = new UnitOfWork(Connection.Products))
{
var sql = "Popularity_Update #TermID";
var parameters = new SqlParameter("TermID", termID);
uow.Execute(sql, parameters);
}
}

Using JOIN with Linq to SQL ExecuteQuery Issue

I have been using Linq to SQL for a while now on one of my sites and over time the code I am using to query the database has gotten a little messy so I decided to re-write, originally my queries were all handled exclusively by Linq but recently there has been a demand for more advanced search features which has led me more towards using ExecuteQuery and handwriting my SQL statements the problem is that I cannot for the life of me get the Join statement to work properly.
I have two tables in my databases, t_events and t_clients. The only thing similar between the two tables is that they both have a clientid field (the id of the client the event is for). What I need to be able to do is pull all of the events into the page (which works fine) but I dont want to show the clientid on the page I need to show the client name. Originally I had a join clause that handled this nicely:
var eve = from p in db.t_events
join c in db.Clients on p.clientid equals c.clientid
where p.datedue <= thisDay && p.status != "complete"
select new { p.eventname, p.datedue, p.details, p.eventid, p.status, c.clientname };
With the redesign of the page however I am having issues recreating what linq has done here with the join. My current code:
StringBuilder sqlQuery = new StringBuilder("SELECT * FROM dbo.t_events JOIN dbo.t_clients ON dbo.t_events.clientid=dbo.t_clients.clientid");
var query = db.ExecuteQuery<t_events>(sqlQuery.ToString());
foreach (var c in query)
{
counter = counter + 1;
MyStringBuilder.Append("<tr class='"+c.status+"'><td><a href='searchdetails.aspx?id="+c.eventid+"'>"+c.eventname+"</a></td><td>" +c.clientname+ "</td></tr>");
}
in the foreach loop I have you can see I am trying to pull in c.clientname (which doesnt work) as it is not on the t_events database, changing this to c.clientid makes the code work, I am not sure what the issue is as taking that same SQL and running the query directly off the sql management tool works like a charm. Any ideas on this issue would be greatly appreciated!
FIXED!
DaveMarkle suggested using a view, which was by far a much easier way of doing this. I created a view that joins the two tables together with the fields I need and run my queries against it, simple and effective, I thank you!
Erm - so maybe we should have an answer here then so the question drops off the 'unanswered' list.
As Dave Markle stated.
Use a view.
Another option!
Execute the query twice: once with db.ExecuteQuery<t_events> and once db.ExecuteQuery<t_clients>. Now that you have both events and clients you can re-join them client-side by matching client_id.

Is there a way to do the google did you mean in linq?

I have list of words. I type in a word misspelled. Can I query the list using linq to get words that sounds like (soundex) the misspelled word?
I believe you can.
A quick google search came up with this link:
Code Snippet
from elt in SomeTable.AsEnumerable()
where SoundEx(elt.SomeWordsSoundExCode) == SoundEx("MyWord")
select elt;
If you want to use LINQ to SQL to query database, then you'll probably want to run the comparison on SQL side. You could use AsEnumerable, but then you'll need to implement the algorithm in C# and process the data in-memory.
I believe that LINQ to SQL doesn't provide any built-in method that would be translated to a call to the SOUNDEX function in SQL. However, you can add mapping for a user-defined SQL function (See for example this article). So, you could define your SQL function that performs the comparison and then write something like:
var db = new MyDatabaseContext();
var q = from w in db.Products
where db.SimilarSoundEx(w.Name, searchInput)
select w;

The question about the basics of LINQ to SQL

I just started learning LINQ to SQL, and so far I'm impressed with the easy of use and good performance.
I used to think that when doing LINQ queries like
from Customer in DB.Customers where Customer.Age > 30 select Customer
LINQ gets all customers from the database ("SELECT * FROM Customers"), moves them to the Customers array and then makes a search in that Array using .NET methods. This is very inefficient, what if there are hundreds of thousands of customers in the database? Making such big SELECT queries would kill the web application.
Now after experiencing how actually fast LINQ to SQL is, I start to suspect that when doing that query I just wrote, LINQ somehow converts it to a SQL Query string
SELECT * FROM Customers WHERE Age > 30
And only when necessary it will run the query.
So my question is: am I right? And when is the query actually run?
The reason why I'm asking is not only because I want to understand how it works in order to build good optimized applications, but because I came across the following problem.
I have 2 tables, one of them is Books, the other has information on how many books were sold on certain days. My goal is to select books that had at least 50 sales/day in past 10 days. It's done with this simple query:
from Book in DB.Books where (from Sale in DB.Sales where Sale.SalesAmount >= 50 && Sale.DateOfSale >= DateTime.Now.AddDays(-10) select Sale.BookID).Contains(Book.ID) select Book
The point is, I have to use the checking part in several queries and I decided to create an array with IDs of all popular books:
var popularBooksIDs = from Sale in DB.Sales where Sale.SalesAmount >= 50 && Sale.DateOfSale >= DateTime.Now.AddDays(-10) select Sale.BookID;
BUT when I try to do the query now:
from Book in DB.Books where popularBooksIDs.Contains(Book.ID) select Book
It doesn't work! That's why I think that we can't use thins kinds of shortcuts in LINQ to SQL queries, like we can't use them in real SQL. We have to create straightforward queries, am I right?
You are correct. LINQ to SQL does create the actual SQL to retrieve your results.
As for your shortcuts, there are ways to work around the limitations:
var popularBooksIds = DB.Sales
.Where(s => s.SalesAmount >= 50
&& s.DateOfSale >= DateTime.Now.AddDays(-10))
.Select(s => s.Id)
.ToList();
// Actually should work.
// Forces the table into memory and then uses LINQ to Objects for the query
var popularBooksSelect = DB.Books
.ToList()
.Where(b => popularBooksIds.Contains(b.Id));
Yes, query gets translated to a SQL string, and the underlying SQL can be different depending on what you are trying to do... so you have to be careful in that regard. Checkout a tool called linqpad, you can try your query in it and see the executing SQL.
Also, it runs when iterating through the collection or calling a method on it like ToList().
Entity framework or linq queries can be tricky sometimes. Sometimes you are surprised at the efficiency of the sql query generated and sometimes the query is so complicated and inefficient that you would smack your forehead.
Best idea is that if you have any suspicions about a query, run an sql profiler at the backend that would monitor all the queries coming in. That way you know exactly what is being passed on to the sql server and correct any inefficiencies if need be.
http://damieng.com/blog/2008/07/30/linq-to-sql-log-to-debug-window-file-memory-or-multiple-writers
This will help you to see what and when queries are being run. Also, Damiens blog is full of other linq to sql goodness.
You can generate an EXISTS clause by using the .Any method. I have had more success that way than trying to generate IN clauses, because it likes to retrieve all the data and pass it all back in as parameters to a query
In linq to sql, IQueryable expression fragments can be combined to create a single query, it will try to keep everything as an IQueryable for as long as it can, before you do something that cannot be expressed in SQL. When you call ToList you are directly asking it to resolve that query into an IEnumerable stored in memory.
In most cases you are better off not selecting the book ids in advance. Keep the fragment for popular books in a single place in the code and use it when necessary, to build on another query. An IQueryable is just an expression tree, which is resolved into SQL at some other point.
If you think your application will perform better by storing the popular books elsewhere (memcache or whatever), then you may consider pulling them out before hand, and checking against that later. This will mean each book id will be passed in as a sproc parameter and used in an IN clause.

Multivalued parameter within T-SQL Query

I am working on .aspx page that uses a t-sql query that uses a multivalued input parameter (a set of labnames) using an array that would store all the labnames prior to running the query.
I have the following parameters for the query.
With c.Parameters
.Add(New SqlParameter("#sdate", sdate.text))
.Add(New SqlParameter("#edate", edate.text))
.Add(New SqlParameter("#labname", SqlDbType.Text)).Value = labnamesparam.ToString
End With
However, I still see that only one labname (3rd param in the order).
Any ideas on this?
For SQL 2008 your should use a TVP, as recommended by Marc.
For SQL 2005 there are several techniques like using XML or using a comma delimitted list. A comprehensive analysis of each technique is kept by Erland Sommarskog on hi page at http://www.sommarskog.se/arrays-in-sql-2005.html.
For SQL 2000 the options are fewer, and again Erland has a comprehensive discussion of each at Arrays and Lists in SQL Server (SQL 2000 and Earlier).
I highly recommend Erland's articles, they've been the reference on the subject for many years now.
You need to turn the contest of the array into a string. Here is a c# example, certainly not the only way to do it.
System.Text.StringBuilder k = new System.Text.StringBuilder();
foreach (string x in LABNAMES) {
k.Append(x);
k.Append(",");
}
.Add(New SqlParameter("#labname", SqlDbType.Text)).Value =k.ToString();
Your going to have to change your sql though you can't have a dynamic in clause like that. Old trick but not good practice is to turn the whole sql into a string and do an execute one it.
You might have to do a little bit more work in your stored procedure if you want to pass along an array of strings to it and perform a T-SQL "IN" operation.
This article has a very good example.
IF you use SQL Server 2008, you could use the "table-valued parameter" (TVP) feature.
Basically, in SQL Server 2008, you need to define a user-defined table type:
CREATE TYPE Customer AS
TABLE (id int, CustomerName nvarchar(50), postcode nvarchar(50))
and then use that in your stored procedure as a parameter:
CREATE Procedure AddCustomers(#customer Customer READONLY)
And then in your C# code, you'd create a DataTable variable of the same structure, and use that as the input parameter. That way, you can pass in any number of values, and any structure you like.
See these excellent blog posts for more information and extensive code samples:
Guy Burstein
Ben Hall
SQL-Team
Marc

Resources