实体框架标量函数上的Bit-Bool引发'无法翻译'异常

Pri*_*ERO 7 c# linq entity-framework

我有许多工作实体框架标量函数.但是,当我尝试通过标量函数返回'truthy'值时,我得到以下异常:

"ETC.Operations.DbClient.DbClient.Data.DbClientContext"类型上指定的方法"Boolean svfn_CanCloneDocument(Int32,System.String)"无法转换为LINQ to Entities存储表达式.

  • 在SQL MANAGEMENT STUDIO中运行时,标量函数可以正常工作
  • 更改RETURN TYPE似乎不起作用.

我试过将RETURN TYPE改为......

  • INT
  • 宾语
  • 布尔

为什么这会失败?

打电话看起来像:

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);
}
Run Code Online (Sandbox Code Playgroud)

让我们看起来像:

[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();
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 4

我有很多工作实体框架标量函数

问题是,在LINQ to Entities查询中使用的数据库上下文中是否还有其他可用的自定义标量函数?

您专注于bool返回类型,但异常消息指示未映射函数(当 LINQ 查询使用无法转换为 SQL 的未知自定义方法时,EF6 会引发相同的异常)。

正如在将函数添加到实体模型中提到的:

在调用任何代码之前先调用函数,FunctionConvention或者FunctionConvention<TFunctions>必须添加到DbModelBuilderDbContext,函数使用的复杂类型也是如此

您需要将以下行添加到您的DbClientContextOnModelCreating覆盖中:

modelBuilder.Conventions.Add(new FunctionConvention<DbClientContext>());
Run Code Online (Sandbox Code Playgroud)

忘记这样做可以让您在 LINQ to Entities 查询之外使用像这样的标量函数,例如

var result = dbContext.svfn_CanCloneDocument(...);
Run Code Online (Sandbox Code Playgroud)

但在 LINQ to Entities 查询中使用时会导致上述运行时异常。

通过注册它们FunctionConvention可以正确处理后面的场景。