Вызов пользовательской функции SQL в запросе LINQ
Мне сложно с этим справиться. Я пытаюсь выполнить поиск по радиусу, используя следующий помощник фильтра на IQueryable. Существует ряд других фильтров, которые применяются до применения RadiusSearch. Порядок не имеет особого значения, поскольку цель состоит в том, чтобы отложить запрос до операции ToList().
public static IQueryable<ApiSearchCommunity> RadiusSearch(this IQueryable<ApiSearchCommunity> communities)
{
var centerLatitude = 30.421278;
var centerLongitude = -97.426261;
var radius = 25;
return communities.Select(c => new ApiSearchCommunity()
{
CommunityId = c.CommunityId,
City = c.City,
//Distance = c.GetArcDistance(centerLatitude, centerLongitude, c.Latitude, c.Longitude, radius)
});
}
Можно ли каким-то образом написать помощника, такого как GetArcDistance, который, в свою очередь, вызывает UDF на SQL? Запрос, который я пытаюсь создать, следующий
SELECT
comms.community_id,
comms.city,
comms.distance
FROM (
SELECT
c.community_id,
c.city,
dbo.udf_ArcDistance(
30.421278,-97.426261,
c.community_latitude,
c.community_longitude
) AS distance
FROM communities c) AS comms
WHERE comms.distance <= 25
ORDER BY comms.distance
Ответы
Ответ 1
Хорошо, думаю, я понимаю вопрос - суть в том, что вы хотите иметь возможность вызывать SQL UDF как часть вашего запроса Linq to Entities.
Это если вы сначала используете базу данных или модель:
В этой статье объясняется, как это сделать: http://msdn.microsoft.com/en-us/library/dd456847(VS.100).aspx
Чтобы подвести итог, сначала вам нужно отредактировать файл edmx в редакторе xml, в разделе edmx: StorageModels → Schema вам нужно указать сопоставление с вашим sql udf, например
<Function Name="SampleFunction" ReturnType="int" Schema="dbo">
<Parameter Name="Param" Mode="In" Type="int" />
</Function>
Затем вам нужно создать статическую функцию где-нибудь с атрибутом EdmFunction, что-то вроде этого:
public static class ModelDefinedFunctions
{
[EdmFunction("TestDBModel.Store", "SampleFunction")]
public static int SampleFunction(int param)
{
throw new NotSupportedException("Direct calls are not supported.");
}
}
Этот метод будет отображаться в UDF во время запроса по структуре сущности. Первый атрибут атрибута - пространство имен хранилища - вы можете найти это в своем XML файле edmx в элементе Schema (посмотрите на пространство имен). Второй аргумент - имя udf.
Затем вы можете вызвать его примерно так:
var result = from s in context.UDFTests
select new
{
TestVal = ModelDefinedFunctions.SampleFunction(22)
};
Надеюсь, что это поможет.
Ответ 2
если вы используете подход Code-First
, тогда вы не можете вызывать UDF как хотите (с EF6) - вот доказательство и еще один. Вы ограничены только вызовом UDF в качестве части вашего SQL-запроса:
bool result = FooContext.CreateQuery<bool>(
"SELECT VALUE FooModel.Store.UserDefinedFunction(@someParameter) FROM {1}",
new ObjectParameter("someParameter", someParameter)
).First();
который является уродливым IMO и подверженным ошибкам.
Кроме того - на этой странице MSDN говорится:
Процесс вызова пользовательской функции требует трех основных шагов:
- Определите функцию в вашей концептуальной модели или объявите функцию в своей модели хранения.
что по существу означает, что вам нужно использовать подход Model-First
для вызова UDF.