代码之家  ›  专栏  ›  技术社区  ›  Prisoner ZERO

实体框架上的位bool标量函数引发“无法转换”异常

  •  6
  • Prisoner ZERO  · 技术社区  · 7 年前

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

    指定的方法'boolean svfn_canclonedocument(int32, 类型上的 “etc.operations.dbclient.dbclient.data.dbclientContext”不能为 转换为LINQ to Entities存储表达式。

    • 在SQL Management Studio中运行时,标量函数起作用
    • 更改返回类型似乎不起作用。

    我尝试将返回类型更改为…

    • 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);
    }
    

    let函数如下:

    [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 回复  |  直到 7 年前
        1
  •  4
  •   Prisoner ZERO    7 年前

    bool

    Add functions to entity model

    FunctionConvention FunctionConvention<TFunctions> DbModelBuilder DbContext

    DbClientContext OnModelCreating

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

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