Skip to content

Commit 55c1900

Browse files
authored
Error while calling Postgresql function by using Database First (#151)
Closes #150
1 parent f07c45c commit 55c1900

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

EF6.PG.Tests/EntityFrameworkBasicTests.cs

+25
Original file line numberDiff line numberDiff line change
@@ -889,5 +889,30 @@ public void Test_enum_composite_key()
889889
Assert.That(result.TestLong, Is.EqualTo(TestLongEnum.Bar));
890890
}
891891
}
892+
893+
[Test]
894+
public void Test_non_composable_function()
895+
{
896+
using (var context = new BloggingContext(ConnectionString))
897+
{
898+
context.Database.Log = Console.Out.WriteLine;
899+
900+
// Add some data and query it back using Stored Function
901+
context.Blogs.Add(new Blog
902+
{
903+
Name = "Some blog1 name",
904+
Posts = new List<Post>()
905+
});
906+
context.SaveChanges();
907+
908+
// Query back
909+
var nameParameter = new ObjectParameter("Name", "blog1");
910+
var blogs = ((IObjectContextAdapter)context).ObjectContext.ExecuteFunction<Blog>("GetBlogsByName2", nameParameter).ToArray();
911+
912+
Assert.AreEqual(1, blogs.Length);
913+
Assert.AreEqual("Some blog1 name", blogs[0].Name);
914+
}
915+
}
916+
892917
}
893918
}

EF6.PG.Tests/Support/EntityFrameworkTestBase.cs

+64
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public abstract class EntityFrameworkTestBase : TestBase
3838
createSequenceConn.ExecuteNonQuery("CREATE OR REPLACE FUNCTION \"dbo\".\"StoredAddFunction\"(integer, integer) RETURNS integer AS $$ SELECT $1 + $2; $$ LANGUAGE SQL;");
3939
createSequenceConn.ExecuteNonQuery("CREATE OR REPLACE FUNCTION \"dbo\".\"StoredEchoFunction\"(integer) RETURNS integer AS $$ SELECT $1; $$ LANGUAGE SQL;");
4040
createSequenceConn.ExecuteNonQuery("CREATE OR REPLACE FUNCTION \"dbo\".\"GetBlogsByName\"(text) RETURNS TABLE(\"BlogId\" int, \"Name\" text, \"IntComputedValue\" int) as $$ select \"BlogId\", \"Name\", \"IntComputedValue\" from \"dbo\".\"Blogs\" where \"Name\" ilike '%' || $1 || '%' $$ LANGUAGE SQL;");
41+
createSequenceConn.ExecuteNonQuery("CREATE OR REPLACE FUNCTION \"dbo\".\"GetBlogsByName2\"(text) RETURNS TABLE(\"BlogId\" int, \"Name\" text, \"IntComputedValue\" int) as $$ select \"BlogId\", \"Name\", \"IntComputedValue\" from \"dbo\".\"Blogs\" where \"Name\" ilike '%' || $1 || '%' $$ LANGUAGE SQL;");
4142
}
4243
}
4344

@@ -336,8 +337,71 @@ private static DbCompiledModel CreateModel(NpgsqlConnection connection)
336337
new FunctionImportResultMapping(),
337338
dbModel.ConceptualToStoreMapping));
338339

340+
341+
var getBlogs2Func = EdmFunction.Create(
342+
"GetBlogsByName2",
343+
"BloggingContext",
344+
DataSpace.SSpace,
345+
new EdmFunctionPayload
346+
{
347+
ParameterTypeSemantics = ParameterTypeSemantics.AllowImplicitConversion,
348+
Schema = "dbo",
349+
IsComposable = false,
350+
IsNiladic = false,
351+
IsBuiltIn = false,
352+
IsAggregate = false,
353+
StoreFunctionName = "GetBlogsByName2",
354+
ReturnParameters = new[]
355+
{
356+
FunctionParameter.Create("ReturnType1", rowType.GetCollectionType(), ParameterMode.ReturnValue)
357+
},
358+
Parameters = new[]
359+
{
360+
FunctionParameter.Create("Name", stringStoreType, ParameterMode.In)
361+
}
362+
},
363+
null);
364+
dbModel.StoreModel.AddItem(getBlogs2Func);
365+
366+
EdmFunction getBlogs2FuncModel = EdmFunction.Create(
367+
"GetBlogsByName2",
368+
dbModel.ConceptualModel.Container.Name,
369+
DataSpace.CSpace,
370+
new EdmFunctionPayload
371+
{
372+
IsFunctionImport = true,
373+
IsComposable = false,
374+
Parameters = new[]
375+
{
376+
FunctionParameter.Create("Name", stringPrimitiveType, ParameterMode.In)
377+
},
378+
ReturnParameters = new[]
379+
{
380+
FunctionParameter.Create("ReturnType1", modelBlogConceptualType.GetCollectionType(), ParameterMode.ReturnValue)
381+
},
382+
EntitySets = new[]
383+
{
384+
dbModel.ConceptualModel.Container.EntitySets.First(x => x.ElementType == modelBlogConceptualType)
385+
}
386+
},
387+
null);
388+
dbModel.ConceptualModel.Container.AddFunctionImport(getBlogs2FuncModel);
389+
390+
dbModel.ConceptualToStoreMapping.AddFunctionImportMapping(new FunctionImportMappingNonComposable(
391+
getBlogs2FuncModel,
392+
getBlogs2Func,
393+
new FunctionImportResultMapping[] { },
394+
dbModel.ConceptualToStoreMapping));
395+
396+
339397
var compiledModel = dbModel.Compile();
340398
return compiledModel;
341399
}
400+
401+
protected override void OnModelCreating(DbModelBuilder modelBuilder)
402+
{
403+
//modelBuilder.Conventions.Add(new FunctionsConvention<MyContext>("dbo"));
404+
base.OnModelCreating(modelBuilder);
405+
}
342406
}
343407
}

EF6.PG/NpgsqlServices.cs

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ internal void TranslateCommandTree(Version serverVersion, DbCommandTree commandT
7979
DbInsertCommandTree insert;
8080
DbUpdateCommandTree update;
8181
DbDeleteCommandTree delete;
82+
DbFunctionCommandTree function;
8283
if ((select = commandTree as DbQueryCommandTree) != null)
8384
sqlGenerator = new SqlSelectGenerator(select);
8485
else if ((insert = commandTree as DbInsertCommandTree) != null)
@@ -87,6 +88,8 @@ internal void TranslateCommandTree(Version serverVersion, DbCommandTree commandT
8788
sqlGenerator = new SqlUpdateGenerator(update);
8889
else if ((delete = commandTree as DbDeleteCommandTree) != null)
8990
sqlGenerator = new SqlDeleteGenerator(delete);
91+
else if ((function = commandTree as DbFunctionCommandTree) != null)
92+
sqlGenerator = new SqlFunctionGenerator(function);
9093
else
9194
{
9295
// TODO: get a message (unsupported DbCommandTree type)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Linq;
2+
using System.Data.Common;
3+
using System.Data.Entity.Core.Common.CommandTrees;
4+
5+
namespace Npgsql.SqlGenerators
6+
{
7+
class SqlFunctionGenerator : SqlBaseGenerator
8+
{
9+
readonly DbFunctionCommandTree _commandTree;
10+
11+
public SqlFunctionGenerator(DbFunctionCommandTree commandTree)
12+
{
13+
_commandTree = commandTree;
14+
}
15+
16+
public override void BuildCommand(DbCommand command)
17+
{
18+
var paramStr = string.Join(",", command.Parameters.OfType<DbParameter>().Select(x => "@" + x.ParameterName).ToArray());
19+
command.CommandText = $"SELECT * FROM { QuoteIdentifier(_commandTree.EdmFunction.Schema) }.{ QuoteIdentifier(_commandTree.EdmFunction.Name) } ({paramStr})";
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)