首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >调用LINQ语句w/o中的标量函数EDMX

调用LINQ语句w/o中的标量函数EDMX
EN

Stack Overflow用户
提问于 2018-05-29 19:47:00
回答 1查看 681关注 0票数 2

我试图在EF中调用SQL标量函数。我试过不同的例子,但我不断得到:

类型y上的指定方法x不能转换为LINQ实体存储表达式。

我用的是.

  • EF 6.1.3
  • EntityFramework.Functions 1.4.1

查询:

注意我在选择中调用它..。

代码语言:javascript
复制
public IQueryable<MeterDataItem> Query()
{
    var query = from meter in UnitOfWork.Meter
                join meterType in UnitOfWork.MeterType on meter.MeterTypeId equals meterType.Id into meterTypeLEFTJOIN
                    from meterType in meterTypeLEFTJOIN.DefaultIfEmpty()
                join company in UnitOfWork.Company on meter.CompanyId equals company.Id
                join meterPosition in UnitOfWork.EFMMeterPosition on meter.EFMMeterPositionId equals meterPosition.Id into meterPositionLEFTJOIN
                    from meterPosition in meterPositionLEFTJOIN.DefaultIfEmpty()
                join flowType in UnitOfWork.FlowType on meter.FlowTypeId equals flowType.Id into flowTypeLEFTJOIN
                    from flowType in flowTypeLEFTJOIN.DefaultIfEmpty()
                join fluidType in UnitOfWork.FluidType on meter.FluidTypeId equals fluidType.Id into fluidTypeLEFTJOIN
                    from fluidType in fluidTypeLEFTJOIN.DefaultIfEmpty()
                join runStatus in UnitOfWork.RunStatus on meter.RunStatusId equals runStatus.Id into runStatusLEFTJOIN
                    from runStatus in runStatusLEFTJOIN.DefaultIfEmpty()
                join pipeline in UnitOfWork.Pipeline on meter.PipelineId equals pipeline.Id into pipelineLEFTJOIN
                    from pipeline in pipelineLEFTJOIN.DefaultIfEmpty()

                // Device portion
                join device in UnitOfWork.Device on meter.DeviceId equals device.Id into deviceLEFTJOIN
                    from device in deviceLEFTJOIN.DefaultIfEmpty()
                join rtuDevice in UnitOfWork.RTUDevice on device.Id equals rtuDevice.DeviceId into rtuDeviceLEFTJOIN
                    from rtuDevice in rtuDeviceLEFTJOIN.DefaultIfEmpty()

                // Contact portion
                join measureTech in UnitOfWork.User on rtuDevice.MeasurementTechnicianId equals measureTech.Id into measureTechLEFTJOIN
                    from measureTech in measureTechLEFTJOIN.DefaultIfEmpty()
                join commTech in UnitOfWork.User on rtuDevice.CommunicationTechnicianId equals commTech.Id into commTechLEFTJOIN
                    from commTech in commTechLEFTJOIN.DefaultIfEmpty()

                // Connection portion
                join deviceCircuit in UnitOfWork.DeviceCircuit on device.Id equals deviceCircuit.DeviceId into deviceCircuitLEFTJOIN
                    from deviceCircuit in deviceCircuitLEFTJOIN.DefaultIfEmpty()
                join circuit in UnitOfWork.Circuit on deviceCircuit.CircuitId equals circuit.Id
                join circuitConnection in UnitOfWork.CircuitConnection on circuit.Id equals circuitConnection.CircuitId
                join connection in UnitOfWork.Connection on circuitConnection.ConnectionId equals connection.Id

                where
                    deviceCircuit.IsPrimary == true

                select new MeterDataItem()
                {
                    MeterId = meter.Id,
                    MeterNumber = meter.MeterNumber,
                    MeterName = meter.MeterName,
                    MeterTypeId = meterType.Id,
                    MeterTypeName = meterType.MeterTypeName,
                    MeterPositionCategory = meterPosition.EFMMeterPositionCategory,
                    FlowTypeName = flowType.FlowTypeName,
                    FluidTypeCategory = fluidType.FluidTypeCategory,
                    RunStatusCategory = runStatus.RunStatusCategory,
                    PipelineName = pipeline.PipelineName,
                    CompanyName = company.CompanyName,
                    ConnectionValue = GetConnection(circuitConnection.Id, connection.ConnectionTypeName),
                    DeviceId = device.Id,
                    DeviceName = device.DeviceName,
                    MeasurementTechnicianId = measureTech.Id,
                    MeasurementTechnicianFirstName = measureTech.FirstName,
                    MeasurementTechnicianLastName = measureTech.LastName,
                    CommunicationTechnicianId = commTech.Id,
                    CommunicationTechnicianFirstName = commTech.FirstName,
                    CommunicationTechnicianLastName = commTech.LastName,
                    MeterObjectStateName = null,    //<-- Default Value
                    FavoriteId = 0                  //<-- Default Value
                };

    return query.OrderBy(x => x.MeterNumber);
}

CSHARP-函数:

我猜因为某种原因它找不到功能..。

代码语言:javascript
复制
[Function(FunctionType.ComposableScalarValuedFunction, nameof(svfn_GetMeterConnection), Schema = "dbo")]
[return: Parameter(DbType = "VARCHAR(100)")]
public string svfn_GetMeterConnection([Parameter(DbType = "INT")]int circuitConnectionId, [Parameter(DbType = "VARCHAR(50)")]string connectionTypeName)
{
    ObjectParameter circuitConnectionIdParameter = new ObjectParameter("@CircuitConnectionId", circuitConnectionId);
    ObjectParameter connectionTypeNameParameter = new ObjectParameter("@ConnectionTypeName", connectionTypeName);

    return UnitOfWork.DbContext.ObjectContext().ExecuteFunction<string>(nameof(this.svfn_GetMeterConnection), circuitConnectionIdParameter, connectionTypeNameParameter).SingleOrDefault();
}

SQL-函数:

我所有的名字和参数名引用看起来都是对的..。

代码语言:javascript
复制
ALTER FUNCTION [dbo].[svfn_GetMeterConnection]
(
    @CircuitConnectionId INT,
    @ConnectionTypeName VARCHAR(50)
)
RETURNS VARCHAR(100)
AS
BEGIN

    DECLARE @Value VARCHAR(100) = NULL;

    -- DIAL-UP
    IF(@ConnectionTypeName = 'Dial-Up')
    BEGIN
        SELECT
            @Value = circuitConnectionConfiguration.ConnectionPropertyValue
        FROM [dbo].[CircuitConnectionConfiguration] circuitConnectionConfiguration
        JOIN [dbo].[ConnectionConfiguration] connectionConfiguration ON connectionConfiguration.Id = circuitConnectionConfiguration.ConnectionConfigurationId
        JOIN [dbo].[ConnectionProperty] connProperty ON connProperty.Id = connectionConfiguration.ConnectionPropertyId
        WHERE
            circuitConnectionConfiguration.CircuitConnectionId = @CircuitConnectionId
            AND connProperty.ConnectionPropertyName = 'Dial-Up Number'
    END

    -- INTERNET PROTOCOL (IP)
    IF(@ConnectionTypeName = 'Internet Protocol (IP)')
    BEGIN
        SELECT @Value = 
            ((SELECT circuitConnectionConfiguration.ConnectionPropertyValue
                FROM [dbo].[CircuitConnectionConfiguration] circuitConnectionConfiguration
                JOIN [dbo].[ConnectionConfiguration] connectionConfiguration ON connectionConfiguration.Id = circuitConnectionConfiguration.ConnectionConfigurationId
                JOIN [dbo].[ConnectionProperty] connProperty ON connProperty.Id = connectionConfiguration.ConnectionPropertyId
            WHERE
                circuitConnectionConfiguration.CircuitConnectionId = @CircuitConnectionId
                AND connProperty.ConnectionPropertyName = 'IP Address') 
            + ':' +
            (SELECT circuitConnectionConfiguration.ConnectionPropertyValue
                FROM [dbo].[CircuitConnectionConfiguration] circuitConnectionConfiguration
                JOIN [dbo].[ConnectionConfiguration] connectionConfiguration ON connectionConfiguration.Id = circuitConnectionConfiguration.ConnectionConfigurationId
                JOIN [dbo].[ConnectionProperty] connProperty ON connProperty.Id = connectionConfiguration.ConnectionPropertyId
            WHERE
                circuitConnectionConfiguration.CircuitConnectionId = @CircuitConnectionId
                AND connProperty.ConnectionPropertyName = 'Port'))
    END

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

更新-回答:

我需要的一些更改包括:

  • 将函数类型更改为FunctionType.ComposableScalarValuedFunction
  • 将DbType参数字符串更改为小写
  • 确保不将大小包含在DbType声明中:将VACHAR(50)更改为varchar
  • 将调用移到具体的DbContext中
  • 在具体的DbContext的FunctionConvention中注册OnModelCreating

混凝土DBCONTEXT:

包括名字空间..。

代码语言:javascript
复制
using EntityFramework.Functions;
using StructureMap;
using System.Configuration;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Linq;

public class MeasurementContractsDbContext : BaseDbContext
{
    #region <Constructors>

    [DefaultConstructor]
    public MeasurementContractsDbContext() : base(Settings.ConnectionString.Database.MeasurementContractsDb)
    {
        Database.SetInitializer<MeasurementContractsDbContext>(null);
        Database.CommandTimeout = int.Parse(ConfigurationManager.AppSettings[Settings.Command.TimeoutInterval]);
        Configuration.ProxyCreationEnabled = false;
    }

    #endregion

    #region <Methods>

    [Function(FunctionType.ComposableScalarValuedFunction, nameof(svfn_GetMeterConnection), Schema = "dbo")]
    [return: Parameter(DbType = "varchar")]
    public string svfn_GetMeterConnection(int circuitConnectionId, string connectionTypeName)
    {
        ObjectParameter circuitConnectionIdParameter = new ObjectParameter("CircuitConnectionId", circuitConnectionId);
        ObjectParameter connectionTypeNameParameter = new ObjectParameter("ConnectionTypeName", connectionTypeName);

        return this.ObjectContext().ExecuteFunction<string>(nameof(this.svfn_GetMeterConnection), circuitConnectionIdParameter, connectionTypeNameParameter).SingleOrDefault();
    }

    [Function(FunctionType.ComposableScalarValuedFunction, nameof(svfn_GetCurrentObjectStateName), Schema = "dbo")]
    [return: Parameter(DbType = "varchar")]
    public string svfn_GetCurrentObjectStateName(int contextId, string contextFullName)
    {
        ObjectParameter contextIdParameter = new ObjectParameter("contextId", contextId);
        ObjectParameter contextFullNameParameter = new ObjectParameter("contextFullName", contextFullName);

        return this.ObjectContext().ExecuteFunction<string>(nameof(this.svfn_GetCurrentObjectStateName), contextIdParameter, contextFullNameParameter).SingleOrDefault();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // ADD Functions
        modelBuilder.Conventions.Add(new FunctionConvention<MeasurementContractsDbContext>());

        // ...
    }

    #endregion
}

示例用法:

代码语言:javascript
复制
/// <exception cref="ArgumentNullException">Non-Existent 'Query' value throws this exception</exception>
public IQueryable<MeterDetailDataItem> AuthorizationToFlowMeterDocumentFilter(IQueryable<MeterDetailDataItem> query)
{
    if (query == null)
        throw new ArgumentNullException("Query");

    string contextFullName = typeof(AuthorizationToFlowMeterDocument).FullName;

    // Get the ATF (if it exists)
    var filteredQuery = (from dataitem in query //<-- QUERY
                        join document in UnitOfWork.Document on dataitem.RequestToFlowMeterDocumentId equals document.ParentId

                         // TODO: Figure out if you can move svfn_GetCurrentObjectStateName into an Algorythm class that can be injected
                         // SQL Function
                         let objectStateName = ((MeasurementContractsDbContext)UnitOfWork.DbContext).svfn_GetCurrentObjectStateName(document.Id, contextFullName)

                        select new MeterDetailDataItem()
                        {
                            MeterId = dataitem.MeterId,
                            RequestToFlowMeterDocumentId = dataitem.RequestToFlowMeterDocumentId,
                            RequestToFlowMeterDocumentObjectStateName = dataitem.RequestToFlowMeterDocumentObjectStateName,
                            AuthorizationToFlowMeterDocumentId = document.Id,
                            AuthorizationToFlowMeterDocumentObjectStateName = objectStateName,
                            FirstDeliveryNoticeDocumentId = dataitem.FirstDeliveryNoticeDocumentId,
                            FirstDeliveryNoticeDocumentObjectStateName = dataitem.FirstDeliveryNoticeDocumentObjectStateName,
                            FavoriteId = dataitem.FavoriteId
                        });

    return filteredQuery.OrderBy(x => x.MeterId);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-30 08:19:36

看起来您正在使用EntityFramework.Functions包。然后看一看函数主题。您使用的是标量值函数,即不可组合的,根据包作者

可以像其他上述方法一样直接调用。

但是,由于它被指定为不可组合的,所以它不能通过LINQ查询中的实体框架进行转换。

这是实体框架的设计

虽然您需要的是标量值函数,可组合的,它

在LINQ实体查询中工作,但不能直接调用。

很短的时间内,由于您在LINQ中使用它,所以在FunctionType.ComposableScalarValuedFunction内使用Function注释。由于它不是直接调用的,所以它不需要方法主体,所以您可以简单地抛出异常:

代码语言:javascript
复制
[Function(FunctionType.ComposableScalarValuedFunction, nameof(svfn_GetMeterConnection), Schema = "dbo")]
public string svfn_GetMeterConnection(int circuitConnectionId, string connectionTypeName)
{
    throw new NotSupportedException();
}

不要忘记如链接中所示注册函数,否则它们将不会生效,您将继续获得NotSupportedException

代码语言:javascript
复制
modelBuilder.Conventions.Add(new FunctionConvention<TheClassContainingTheFunction>());
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50591873

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档