Bit-Bool на Entity Framework Scalar Function Throw «не может быть переведен» Исключение - PullRequest
0 голосов
/ 07 февраля 2019

У меня много работающих скалярных функций Entity Framework.Однако, когда я пытаюсь вернуть «истинное» значение через скалярную функцию, я получаю следующее исключение:

Указанный метод Boolean svfn_CanCloneDocument (Int32, System.String) 'для типа' ETC.Operations.DbClient.DbClient.Data.DbClientContext 'нельзя преобразовать в выражение хранилища LINQ to Entities.

  • Скалярная функция работает при запуске в SQL MANAGEMENT STUDIO
  • Изменение ТИПА ВОЗВРАТА не работает.

Я попытался изменить ТИП ВОЗВРАТА на ...

  • int
  • object
  • bool

Почему это не получается?

ЗВОНИТЕ, КАК НАЗВАТЬ, КАК:

public IQueryable<ShakeoutDataItem> Query()
{
    var uow = UnitOfWork as DbClientUnitOfWork;
    var dbContext = UnitOfWork.DbContext as DbClientContext;

    var query = (from document in dbContext.vDocumentStatus
                 join shakeout in uow.Shakeout on document.DocumentId equals shakeout.DocumentId
                 join shakeoutDetail in uow.ShakeoutDetail on shakeout.Id equals shakeoutDetail.ShakeoutId
                 join meter in uow.Meter on shakeoutDetail.MeterId equals meter.Id
                 join product in uow.Product on shakeout.ProductId equals product.Id into productLEFTJOIN
                 from product in productLEFTJOIN.DefaultIfEmpty()

                 // THIS FAILS
                 let cloneable = dbContext.svfn_CanCloneDocument(document.DocumentId, "SHAKEOUT")

                 select new ShakeoutDataItem()
                 {
                     // Other fields LEFT OUT for BREVITY
                     CanClone = cloneable
                 });

    return query.OrderBy(x => x.DocumentCreatedDate).ThenBy(x => x.SchedulingBatch);
}

LET FUNCTION выглядит так:

[Function(FunctionType.ComposableScalarValuedFunction, nameof(svfn_CanCloneDocument), Schema = "dbo")]
[return: Parameter(DbType = "bit")]
public bool svfn_CanCloneDocument(int documentId, string documentTypeShortName)
{
    ObjectParameter documentIdParameter = new ObjectParameter("documentId", documentId);
    ObjectParameter documentTypeShortNameParameter = new ObjectParameter("documentTypeShortName", documentTypeShortName);

    return this.ObjectContext().ExecuteFunction<bool>(nameof(this.svfn_CanCloneDocument), documentIdParameter, documentTypeShortNameParameter).SingleOrDefault();
}

SQL выглядит так:

CREATE FUNCTION [dbo].[svfn_CanCloneDocument]
(
    @DocumentId INT,
    @DocumentTypeShortName NVARCHAR(50)
)
RETURNS BIT
AS
BEGIN
    /*
        Name: [dbo].[svfn_CanCloneDocument]
        Creation Date: 02/02/2019

        Purpose: Retrieves the Full Name for given User.Id or returns NULL

        Input Parameters:   @DocumentId             = The Id for the DOCUMENT record
                            @DocumentTypeShortName  = The Short Name for the DOCUMENT TYPE record

        Format:             @DocumentId             = 1
                            @DocumentTypeShortName  = SHAKEOUT
    */
    DECLARE @Value BIT = CAST(0 AS BIT);

    -- NOTE: They are going to have more DOCUMENT TYPES later-on.  If the rules for Cloneable are the same...simplify this function
    IF(@DocumentTypeShortName = 'SHAKEOUT')
    BEGIN
        DECLARE @Id INT = (SELECT TOP 1 Id FROM [dbo].[tvfn_ListDocumentDescendants](@DocumentId) WHERE Id <> @DocumentId ORDER BY Id DESC);

        -- CAN CLONE When no Descendants Exist
        SELECT @Value = (CASE 
                            WHEN @Id IS NULL THEN CAST(1 AS BIT)
                            ELSE CAST(0 AS BIT)
                         END)
    END

    -- Return the result of the function
    RETURN @Value
END

1 Ответ

0 голосов
/ 12 февраля 2019

У меня много работающих скалярных функций Entity Framework

Вопрос в том, есть ли у вас другие рабочие скалярные функции в этом контексте дБ, используемом в LINQ to Entities запрос?

Вы концентрируетесь на типе возврата bool, но сообщение об исключении указывает на функцию not mapped (такое же исключение выдается EF6, когда запрос LINQ использует неизвестный пользовательский метод, который не можетбыть переведены на SQL).

Как уже упоминалось в Добавление функций в модель сущности :

Перед вызовом любой функции кода первой, FunctionConvention или FunctionConvention<TFunctions> должен быть добавлен к DbModelBuilder из DbContext, поэтому сложные типы используются функциями

Вам необходимо добавить следующую строку в ваш DbClientContext class OnModelCreating override:

modelBuilder.Conventions.Add(new FunctionConvention<DbClientContext>());

Если вы забудете это сделать, вы сможете использовать скалярные функции, подобные этой, вне запроса LINQ to Entities, например,

var result = dbContext.svfn_CanCloneDocument(...);

, но вызывает вышеупомянутое исключение времени выполнения при использовании внутри LINQ toЗапрос сущностей.

Регистрация их с помощью FunctionConvention позволяет правильно обрабатывать более поздний сценарий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...