Calling a SQL User-defined function in a LINQ query
Ok, I think I understand the question - the gist of it is you want to be able to call a SQL UDF as part of your Linq to Entities query.
This is if you're using database or model first:
This article explains how to do it: http://msdn.microsoft.com/en-us/library/dd456847(VS.100).aspx
To sum it up, you first need to edit your edmx file in an xml editor, in the edmx:StorageModels >> Schema section you need to specify a mapping to your sql udf, eg
<Function Name="SampleFunction" ReturnType="int" Schema="dbo">
<Parameter Name="Param" Mode="In" Type="int" />
</Function>
Then you need to create a static function somewhere with the EdmFunction attribute on it, something like this:
public static class ModelDefinedFunctions
{
[EdmFunction("TestDBModel.Store", "SampleFunction")]
public static int SampleFunction(int param)
{
throw new NotSupportedException("Direct calls are not supported.");
}
}
This method will get mapped to the UDF at query time by entity framework. The first attribute argument is the store namespace - you can find this in your edmx xml file on the Schema element (look for Namespace). The second argument is the name of the udf.
You can then call it something like this:
var result = from s in context.UDFTests
select new
{
TestVal = ModelDefinedFunctions.SampleFunction(22)
};
Hope this helps.
Calling functions in a LINQ query
The problem is that your Linq to Entities provider doesn't know how to translate your custom methods to SQL. The solution proposed by @teovankot is the easy way to solve this problem, but if you want to work with Linq to Objects I suggest you use AsEnumerable
extension method instead ToList
because AsEnumerable
does not execute the query until you consult the data, it preserves deferred execution, but be careful, try to don't use AsEnumerable
or ToList
on the entire DbSet
because you'd retrieve all rows of that table affecting your application's performance.
Now if you only want to check weather Col1
is a numeric value or not, another solution could be using SqlFunctions.IsNumeric method which is translated into native SQL:
using System.Data.Entity.SqlServer;
//...
source.Where(x=> SqlFunctions.IsNumeric(x.Col1)==1);
You can find another set of functions you can also call in the DbFunctions
static class.SqlFunctions
are SQL Server specific, whereas DbFunctions
aren't.
How to call a UDF in a linq to sql query?
Here is the MSDN article:
How to: Call User-Defined Functions Inline (LINQ to SQL)
A note from the same page:
Although you can call user-defined
functions inline, functions that are
included in a query whose execution is
deferred are not executed until the
query is executed. For more
information, see Introduction to LINQ
Queries.When you call the same function
outside a query, LINQ to SQL creates a
simple query from the method call
expression
Also, take a look at this 13 min screencast.
Executing SQL Function Using Linq
I am assuming that you are using a dbml (linq to sql) file.
Drag drop your User defined function from the server explorer in visual studio into your dbml.
Then from the datacontext object of your dbml you can call the function directly.
For example if your dbml file name is xyz.dbml then your datacontext object's name would be 'XyzDataContext', unless you have changed it.
Then try this.
XyzDataContext db = new XyzDataContext();
List<Fn_GetNoLocationAddressResult> = db.Fn_GetNoLocationAddress("site", 25).ToList();
Calling SQL scalar function from Linq Query
Thanks to Gerd Arnold I realize that scalar functions cannot be used inside query where statement.
Here is how I managed to filter my query by calling scalar function outside query:
var result = query.ToList();
for (int i = 0; i < result.Count; i++)
{
// prisustvoPostotci(ID, year) is my scalar function
if (dm.prisustvoPostotci(result[i].ID, max_year).FirstOrDefault() >= 50)
{
result.Remove(result[i]);
i--;
}
}
This way calling scalar function will work and we can remove matching records from the result!
Hope this will help someone.
:: cheers ::
Josip
How to Call SQLite User Defined Function with C# LINQ Query
Woohoo! I got it working.
First, the DbGetValue function doesn't get called when building a query, only when called directly in the code. So the code within it is irrelevant, and when it does get called, you can calculate the value directly without calling the database.
Second, even though the function is defined as "real" in the model, it will work if you change the return value to double instead of float. No idea why.
Third, you must bind the function to the connection with something like this
public static class ExtensionMethods {
public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function) {
var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast<SQLiteFunctionAttribute>().ToArray();
if (attributes.Length == 0) {
throw new InvalidOperationException("SQLiteFunction doesn't have SQLiteFunctionAttribute");
}
connection.BindFunction(attributes[0], function);
}
}
And then call it like this
using (NaturalGroundingVideosEntities context = new NaturalGroundingVideosEntities()) {
SQLiteConnection Conn = (SQLiteConnection)context.Database.Connection;
Conn.Open();
Conn.BindFunction(new fn_CalculateSomething());
listBox1.DataSource = (from v in context.RatingCategories
select v.DbGetValue(5, 5, 5)).ToList();
}
This will work! Then, you might want to do the function binding at a location that is more convenient, but you get the idea.
Good luck!
How to register CLR User Defined Function for use in linq query?
I actually coded up this exact function some time ago. Mine's a bit more general purpose, but it looks like this:
[SqlFunction(DataAccess = DataAccessKind.Read, IsDeterministic = true)]
public static string Replace(string input, string pattern, string replacement, int options)
{
return Regex.Replace(input, pattern, replacement, (RegexOptions)options);
}
You then have to register it in SQL with
CREATE ASSEMBLY [MyAssembly]
FROM 'C:\Path\To\Assembly\MyAssembly.dll'
WITH PERMISSION_SET = SAFE
GO
CREATE FUNCTION [dbo].[Replace](@input [nvarchar](4000), @pattern [nvarchar](4000), @replacement [nvarchar](4000), @options [int] = 0)
RETURNS [nvarchar](4000) NULL
WITH EXECUTE AS CALLER
AS EXTERNAL NAME [MyAssembly].[MyNamespace.UserDefinedFunctions].[Replace]
GO
That will create your CLR-UDF in SQL. I've never tried linking back to a linq query, but I assume it would work like any other EDM function.
[EdmFunction("dbo", "Replace")]
public static string Replace(Replace input, pattern, replace, int flags)
{
throw new NotSupportedException("Direct calls not supported");
}
You might even be able to put SqlFunction
and EdmFunction
attributes on the same method, but I don't recommend it (it also seems like pushing the limit of circularity). I prefer to keep my CLR-UDF functions in a completely separate assembly, since they change very infrequently and my assemblies which consume the data are very dynamic.
Related Topics
Are Java and C# Regular Expressions Compatible
How to Get the Selected Item of a Combo Box to a String Variable in C#
Filesystemwatcher to Watch Unc Path
How to Lock/Unlock a File Across Process
How to Upload File Using Ajax.Beginform() Asynchronously
List<T> Readonly with a Private Set
Why Accessviolationexception Cannot Be Caught by .Net4.0
Print HTML Document from Windows Service in C# Without Print Dialog
Webbrowser Component Not Showing CSS 3
More Elegant Exception Handling Than Multiple Catch Blocks
Entity Framework Initialization Is Slow -- What How to Do to Bootstrap It Faster
Can You Use C++ Dlls in C# Code in a Uwp
Deploying ASP.NET Web Forms Project to Fedora 24
Application Can't Scaffold Items
"Can't Find Pinvoke Dll 'Dbnetlib.Dll'." Error in Smart Device Application