Je voudrais mapper ma fonction scalaire à mon .edmx mais cela échoue. Je fais un clic droit sur le mappage de la structure de mon entité et je choisis le modèle de mise à jour dans la base de données. Il apparaît dans mon dossier de procédures stockées dans mon navigateur de modèles.
Cependant, quand je veux l'ajouter à mon Function Imports
dossier dans le navigateur de modèles, le message la fonction scalaire n'apparaît pas apparaît dans la liste déroulante. Est-ce que quelqu'un peut m'aider?
Je peux appeler la fonction scalaire en utilisant l'ancienne méthode, comme:
dbContext.ExecuteStoreQuery<DateTime?>(
"SELECT dbo.getMinActualLoadDate ({0}, {1}, {2}) AS MyResult",
LoadPkid, LoadFkStartLoc, TripSheetPkid).First();
mais ce n'est pas la meilleure façon. Mon responsable aimerait que je trouve un moyen de mettre la fonction scalaire dans le dossier "import de fonction" afin que je puisse appeler la fonction scalaire en utilisant le code suivant au lieu du code précédent:
dbContext.ExecuteFunction("getMinActualLoadDate ", paramList);
J'ai essayé d'ajouter une image pour montrer ce que je veux dire mais comme ma réputation est encore faible, je ne peux pas le faire. Cependant, l'image peut être trouvée ici: http://social.msdn.Microsoft.com/Forums/en-US/adodotnetentityframework/thread/756865e5-ff25-4f5f-aad8-fed9d741c05d
Merci.
J'ai rencontré le même problème. Et voici la solution que j'ai trouvée suffisamment adaptée (testée dans EF5, mais devrait également fonctionner dans EF4):
La prise en charge des fonctions de valeur scalaire n'est pas prise en charge, mais vous pouvez les exécuter directement.
Vous pouvez également modifier le fichier edmx pour que edmx génère la méthode appropriée pour la fonction de valeur scalaire, mais il sera supprimé si vous synchronisez votre modèle avec la base de données.
Ecrivez vous-même l'implémentation d'une fonction à valeur scalaire:
string sqlQuery = "SELECT [dbo].[CountMeals] ({0})";
Object[] parameters = { 1 };
int activityCount = db.Database.SqlQuery<int>(sqlQuery, parameters).FirstOrDefault();
Ou modifiez edmx et ajoutez Xml pour une cartographie personnalisée de la fonction à valeur scalaire:
<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>
Cette information a été trouvée dans ce article de blog
Voici ma solution à ce problème, qui correspond presque exactement à ce que votre manager demandait .. quoique 18 mois de retard.
Comme méthode à la vanille:
/// <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(schema)) {
throw new ArgumentException("schema");
}
string cmdText =
$@"SELECT {schema}.{sql}({string.Join(",",
parameters.Select(p => "@" + p.ParameterName).ToList())});";
// ReSharper disable once CoVariantArrayConversion
return db.Database.SqlQuery<T>(cmdText, parameters).FirstOrDefault();
}
}
Et comme méthode d'extension à 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 =
$@"SELECT {schema}.{sql}({string.Join(",",
parameters.Select(p => "@" + p.ParameterName).ToList())});";
// ReSharper disable once CoVariantArrayConversion
return db.SqlQuery<T>(cmdText, parameters).FirstOrDefault();
}
}
}
Bien qu'il ne fume pas ici, je suggère des tests unitaires avant toute utilisation sérieuse.
La seule et la seule solution consiste à convertir le type scalaire de fonction en type de valeur de table avec une seule valeur dans le tableau, veuillez consulter l'exemple de code.
Vous n'avez rien à changer dans le XML EDMX, veuillez modifier la fonction SQL
Fonction scalaire telle qu'elle était, ce qui ne fonctionne pas
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.
Fonction scalaire -> Fonction convertie en valeur de table, cela fonctionne
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
Capture d'écran Edmx
Je suppose que vous manquez le Edit Function Import
boîte de dialogue, où vous pouvez générer Types complexes . essayez d'explorer.
Si vous avez réussi à créer le scalars
, vous pouvez maintenant naviguer comme ceci
using (var con = new DatabaseEntities())
{
long? invoiceNo = con.sp_GetInvoiceMaxNumber(code.Length + 2).First();
....
}
Code dans la page:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (MayEntities context = new MayEntities())
{
string str = context.Database.SqlQuery<string>("select dbo.HeyYou()").Single().ToString();
Response.Write(str); //output:'Hey this works'
}
}
}
fonction scalaire:
CREATE FUNCTION [dbo].[HeyYou] ()
RETURNS varchar(20)
AS
BEGIN
RETURN 'Hey this works'
END
go