Могу ли я использовать CAST внутри запроса LINQ to Entities?

У меня есть запрос LINQ to Entities

From item In ctx.Items
Select new {
    ListPrice = item.Cost / (1M - item.Markup)
};

Могу ли я указать EF, что я хочу применить cast к прейскуранту, прежде чем запрашивать и реализовывать его1? Есть ли что-то вроде EntityFunctions.Cast может быть? Или я могу использовать ESQL cast функционировать?

Я хочу, чтобы LINQ генерировал SQL-запрос по этим направлениям.

SELECT cast((Cost / (1 - Markup)) as decimal(10, 2)) AS ListPrice

1 Моя цель - избавиться от кучности точности / масштабирования запроса. Поскольку есть десятичное вычитание и деление, результатом математики является десятичное число (38, 26)! Это намного больше, чем может справиться.NET, и больше, чем мне нужно.

1 ответ

Решение

EF позволяет отображать функции CLR в функции базы данных, используя DbFunctionприписывать. К сожалению, это выглядит как встроенный cast а также convert не являются функциями, и это не похоже, что вы можете сопоставить их.

Вместо этого вы можете создать UDF, который выполняет приведение и отображать его в DbModel, API отображения сложен, поэтому я бы использовал библиотеку Code First Functions, чтобы сделать это для вас. (Если вы сначала используете базу данных или модель, вы можете выполнить сопоставление вручную в SSDL и CSDL 1). Кроме того, нет никакого способа выполнять динамическое приведение внутри UDF, поэтому вам нужно будет выбрать запись отдельных функций для каждого нужного преобразования. Вот пример для cast(field as decimal(10,4),

-- In SQL Server
CREATE FUNCTION ClrRound_10_4
(
    @value decimal(28, 10)
)
RETURNS decimal(10,4)
AS
BEGIN
    DECLARE @converted decimal(10,4)

    SELECT @converted = cast(round(@value, 4) as decimal(10,4))

    RETURN @converted

END
GO
//In your DbContext class
using CodeFirstStoreFunctions;

public class MyContext : DbContext {
    protected override void OnModelCreating(DbModelBuilder builder) {
        builder.Conventions.Add(new FunctionsConvention("dbo", typeof(Udf));
    }

    //etc
}

//In a static class named Udf (in the same namespace as your context)
using System.Data.Entity;

public static class Udf {
    [DbFunction("CodeFirstDatabaseSchema", "ClrRound_10_4")]
    public static decimal ClrRound_10_4(decimal value) {
        throw new InvalidOperationException("Cannot call UDF directly!");
    }
}

//In your LINQ query
from item in ctx.Items
select new {
    ListPrice = Udf.ClrRound_10_4(item.Cost / (1M - item.Markup))
};

1 См. Этот блог или статью MSDN для более подробной информации.

Другие вопросы по тегам