Вызов скалярной функции из С# с использованием Entity Framework 4.0/.edmx
Я хотел бы сопоставить свою скалярную функцию с моим .edmx, но это не удается. Я нажимаю правой кнопкой мыши на моем каркасе структуры сущностей и выбираю модель обновления из базы данных. Он отображается в моей папке хранимых процедур в моем браузере моделей.
Однако, когда я хочу добавить его в мою папку Function Imports
в браузере модели, скалярная функция не отображается в выпадающем списке. Кто-нибудь может мне помочь?
Я могу вызвать скалярную функцию, используя старый способ, например:
dbContext.ExecuteStoreQuery<DateTime?>(
"SELECT dbo.getMinActualLoadDate ({0}, {1}, {2}) AS MyResult",
LoadPkid, LoadFkStartLoc, TripSheetPkid).First();
но это не лучший способ. Мой менеджер хотел бы, чтобы я нашел способ разместить скалярную функцию в папке "функция импорта", чтобы я мог вызвать скалярную функцию, используя следующий код вместо предыдущего кода:
dbContext.ExecuteFunction("getMinActualLoadDate ", paramList);
Я попытался добавить изображение, чтобы показать, что я имею в виду, но поскольку моя репутация по-прежнему низкая, я не могу этого сделать. Однако изображение можно найти здесь: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/756865e5-ff25-4f5f-aad8-fed9d741c05d
Спасибо.
Ответы
Ответ 1
Я столкнулся с той же проблемой. И вот решение, которое я нашел достаточно подходящим для себя (тестировался в EF5, но должен также работать в EF4):
Нет поддержки отображения функций скалярного значения из коробки, но вы можете их выполнить напрямую.
Вы также можете отредактировать файл edmx, чтобы edmx генерировал правильный метод для функции скалярного значения, но он будет удален, если вы будете синхронизировать свою модель с базой данных.
Записать реализацию скалярной функции самостоятельно:
string sqlQuery = "SELECT [dbo].[CountMeals] ({0})";
Object[] parameters = { 1 };
int activityCount = db.Database.SqlQuery<int>(sqlQuery, parameters).FirstOrDefault();
Или отредактируйте edmx и добавьте Xml для пользовательского отображения скалярнозначной функции:
<Function Name="CountActivities" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
<CommandText>
SELECT [dbo].[CountActivities] (@personId)
</CommandText>
<Parameter Name="personId" Type="int" Mode="In" />
</Function>
Эта информация была найдена в этом сообщении
Ответ 2
Вот мое решение этой проблемы, и это почти то, о чем просил ваш менеджер.. хотя и опоздал на 18 месяцев.
В качестве ванильного метода:
/// <summary>
/// Calls a given Sql function and returns a singular value
/// </summary>
/// <param name="db">Current DbContext instance</param>
/// <typeparam name="T">CLR Type</typeparam>
/// <param name="sql">Sql function</param>
/// <param name="parameters">Sql function parameters</param>
/// <param name="schema">Owning schema</param>
/// <returns>Value of T</returns>
public T SqlScalarResult<T>(DbContext db,
string sql,
SqlParameter[] parameters,
string schema = "dbo") {
if (string.IsNullOrEmpty(sql)) {
throw new ArgumentException("function");
}
if (parameters == null || parameters.Length == 0) {
throw new ArgumentException("parameters");
}
if (string.IsNullOrEmpty(sql)) {
throw new ArgumentException("schema");
}
string cmdText =
[email protected]"SELECT {schema}.{sql}({string.Join(",",
parameters.Select(p => "@" + p.ParameterName).ToList())});";
// ReSharper disable once CoVariantArrayConversion
return db.Database.SqlQuery<T>(cmdText, parameters).FirstOrDefault();
}
}
И как метод расширения для EF:
namespace System.Data.Entity {
public static class DatabaseExtensions {
/// <summary>
/// Calls a given Sql function and returns a singular value
/// </summary>
/// <param name="db">Current DbContext instance</param>
/// <typeparam name="T">CLR Type</typeparam>
/// <param name="sql">Sql function</param>
/// <param name="parameters">Sql function parameters</param>
/// <param name="schema">Owning schema</param>
/// <returns>Value of T</returns>
public static T SqlScalarResult<T>(this Database db,
string sql,
SqlParameter[] parameters,
string schema = "dbo") {
if (string.IsNullOrEmpty(sql)) {
throw new ArgumentException("sql");
}
if (parameters == null || parameters.Length == 0) {
throw new ArgumentException("parameters");
}
if (string.IsNullOrEmpty(schema)) {
throw new ArgumentException("schema");
}
string cmdText =
[email protected]"SELECT {schema}.{sql}({string.Join(",",
parameters.Select(p => "@" + p.ParameterName).ToList())});";
// ReSharper disable once CoVariantArrayConversion
return db.SqlQuery<T>(cmdText, parameters).FirstOrDefault();
}
}
}
Хотя он не курит здесь, я предлагаю тестировать устройство перед серьезным использованием.
Ответ 3
Я думаю, вы пропустите диалог Edit Function Import
, где вы можете создавать сложные типы. попытайтесь исследовать.
![enter image description here]()
Если вы успешно создали scalars
, теперь вы можете перемещаться таким образом
using (var con = new DatabaseEntities())
{
long? invoiceNo = con.sp_GetInvoiceMaxNumber(code.Length + 2).First();
....
}
Ответ 4
Единственное решение - преобразовать тип скалярного типа в тип значения таблицы с единственным значением в таблице, см. пример кода.
Вам не нужно ничего менять в EDMX XML, пожалуйста, измените функцию SQL
Скалярная функция как есть, которая не работает
CREATE FUNCTION [dbo].[GetSha256]
(
-- Add the parameters for the function here
@str nvarchar(max)
)
RETURNS VARBINARY(32)
AS
BEGIN
RETURN ( SELECT * FROM HASHBYTES('SHA2_256', @str) AS HASH256 );
END -- this doesn't work.
Скалярная функция → Преобразованная в таблицу Значимая функция, она работает
CREATE FUNCTION [dbo].[GetSha2561]
(
-- Add the parameters for the function here
@str nvarchar(max)
)
RETURNS @returnList TABLE (CODE varbinary(32))
AS
BEGIN
INSERT INTO @returnList
SELECT HASHBYTES('SHA2_256', @str);
RETURN; -- This one works like a charm.
END
Снимок экрана Edmx
![введите описание изображения здесь]()