Вызов пользовательской функции SQL в запросе LINQ

мне трудно заставить это работать. Я пытаюсь выполнить поиск radius, используя следующий помощник фильтра на 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

2 ответов


хорошо, я думаю, что понимаю вопрос - суть в том, что вы хотите иметь возможность вызывать SQL UDF как часть вашего запроса Linq to Entities.

Это если вы используете базу данных или модель первая:

эта статья объясняет, как сделать это: http://msdn.microsoft.com/en-us/library/dd456847(против.100).аспн

чтобы подвести итог, вам сначала нужно отредактировать файл 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 во время запроса Entity framework. Первый аргумент атрибута-пространство имен store - вы можете найти его в xml-файле edmx в элементе схемы (ищите пространство имен). Второй аргумент-это имя UDF.

затем вы можете назвать это чем-то вот так:

var result = from s in context.UDFTests
            select new
            {
                TestVal = ModelDefinedFunctions.SampleFunction(22)
            };

надеюсь, что это помогает.


Если вы используете Code-First подход, то вы не может вызов UDFs, как вы хотите (начиная с EF6) - вот доказательство и еще один. Вы ограничены только вызовом UDF как часть вашего SQL-запроса:

bool result = FooContext.CreateQuery<bool>(
    "SELECT VALUE FooModel.Store.UserDefinedFunction(@someParameter) FROM {1}",
    new ObjectParameter("someParameter", someParameter)
).First();

что уродливо ИМО и подвержено ошибкам.

также - это MSDN страница говорит:

процесс вызова пользовательской функции требует трех основных шагов:

  1. определите функцию в вашей концептуальная модель или объявить функцию в модели хранения.

что по существу означает, что вам нужно использовать Model-First подход к вызову UDFs.