Skip to content

Commit

Permalink
Error while calling Postgresql function by using Database First (npgs…
Browse files Browse the repository at this point in the history
  • Loading branch information
Duy-KMS authored Mar 15, 2020
1 parent f07c45c commit 55c1900
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 0 deletions.
25 changes: 25 additions & 0 deletions EF6.PG.Tests/EntityFrameworkBasicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -889,5 +889,30 @@ public void Test_enum_composite_key()
Assert.That(result.TestLong, Is.EqualTo(TestLongEnum.Bar));
}
}

[Test]
public void Test_non_composable_function()
{
using (var context = new BloggingContext(ConnectionString))
{
context.Database.Log = Console.Out.WriteLine;

// Add some data and query it back using Stored Function
context.Blogs.Add(new Blog
{
Name = "Some blog1 name",
Posts = new List<Post>()
});
context.SaveChanges();

// Query back
var nameParameter = new ObjectParameter("Name", "blog1");
var blogs = ((IObjectContextAdapter)context).ObjectContext.ExecuteFunction<Blog>("GetBlogsByName2", nameParameter).ToArray();

Assert.AreEqual(1, blogs.Length);
Assert.AreEqual("Some blog1 name", blogs[0].Name);
}
}

}
}
64 changes: 64 additions & 0 deletions EF6.PG.Tests/Support/EntityFrameworkTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public abstract class EntityFrameworkTestBase : TestBase
createSequenceConn.ExecuteNonQuery("CREATE OR REPLACE FUNCTION \"dbo\".\"StoredAddFunction\"(integer, integer) RETURNS integer AS $$ SELECT $1 + $2; $$ LANGUAGE SQL;");
createSequenceConn.ExecuteNonQuery("CREATE OR REPLACE FUNCTION \"dbo\".\"StoredEchoFunction\"(integer) RETURNS integer AS $$ SELECT $1; $$ LANGUAGE SQL;");
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;");
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;");
}
}

Expand Down Expand Up @@ -336,8 +337,71 @@ private static DbCompiledModel CreateModel(NpgsqlConnection connection)
new FunctionImportResultMapping(),
dbModel.ConceptualToStoreMapping));


var getBlogs2Func = EdmFunction.Create(
"GetBlogsByName2",
"BloggingContext",
DataSpace.SSpace,
new EdmFunctionPayload
{
ParameterTypeSemantics = ParameterTypeSemantics.AllowImplicitConversion,
Schema = "dbo",
IsComposable = false,
IsNiladic = false,
IsBuiltIn = false,
IsAggregate = false,
StoreFunctionName = "GetBlogsByName2",
ReturnParameters = new[]
{
FunctionParameter.Create("ReturnType1", rowType.GetCollectionType(), ParameterMode.ReturnValue)
},
Parameters = new[]
{
FunctionParameter.Create("Name", stringStoreType, ParameterMode.In)
}
},
null);
dbModel.StoreModel.AddItem(getBlogs2Func);

EdmFunction getBlogs2FuncModel = EdmFunction.Create(
"GetBlogsByName2",
dbModel.ConceptualModel.Container.Name,
DataSpace.CSpace,
new EdmFunctionPayload
{
IsFunctionImport = true,
IsComposable = false,
Parameters = new[]
{
FunctionParameter.Create("Name", stringPrimitiveType, ParameterMode.In)
},
ReturnParameters = new[]
{
FunctionParameter.Create("ReturnType1", modelBlogConceptualType.GetCollectionType(), ParameterMode.ReturnValue)
},
EntitySets = new[]
{
dbModel.ConceptualModel.Container.EntitySets.First(x => x.ElementType == modelBlogConceptualType)
}
},
null);
dbModel.ConceptualModel.Container.AddFunctionImport(getBlogs2FuncModel);

dbModel.ConceptualToStoreMapping.AddFunctionImportMapping(new FunctionImportMappingNonComposable(
getBlogs2FuncModel,
getBlogs2Func,
new FunctionImportResultMapping[] { },
dbModel.ConceptualToStoreMapping));


var compiledModel = dbModel.Compile();
return compiledModel;
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//modelBuilder.Conventions.Add(new FunctionsConvention<MyContext>("dbo"));
base.OnModelCreating(modelBuilder);
}
}
}
3 changes: 3 additions & 0 deletions EF6.PG/NpgsqlServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ internal void TranslateCommandTree(Version serverVersion, DbCommandTree commandT
DbInsertCommandTree insert;
DbUpdateCommandTree update;
DbDeleteCommandTree delete;
DbFunctionCommandTree function;
if ((select = commandTree as DbQueryCommandTree) != null)
sqlGenerator = new SqlSelectGenerator(select);
else if ((insert = commandTree as DbInsertCommandTree) != null)
Expand All @@ -87,6 +88,8 @@ internal void TranslateCommandTree(Version serverVersion, DbCommandTree commandT
sqlGenerator = new SqlUpdateGenerator(update);
else if ((delete = commandTree as DbDeleteCommandTree) != null)
sqlGenerator = new SqlDeleteGenerator(delete);
else if ((function = commandTree as DbFunctionCommandTree) != null)
sqlGenerator = new SqlFunctionGenerator(function);
else
{
// TODO: get a message (unsupported DbCommandTree type)
Expand Down
22 changes: 22 additions & 0 deletions EF6.PG/SqlGenerators/SqlFunctionGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Linq;
using System.Data.Common;
using System.Data.Entity.Core.Common.CommandTrees;

namespace Npgsql.SqlGenerators
{
class SqlFunctionGenerator : SqlBaseGenerator
{
readonly DbFunctionCommandTree _commandTree;

public SqlFunctionGenerator(DbFunctionCommandTree commandTree)
{
_commandTree = commandTree;
}

public override void BuildCommand(DbCommand command)
{
var paramStr = string.Join(",", command.Parameters.OfType<DbParameter>().Select(x => "@" + x.ParameterName).ToArray());
command.CommandText = $"SELECT * FROM { QuoteIdentifier(_commandTree.EdmFunction.Schema) }.{ QuoteIdentifier(_commandTree.EdmFunction.Name) } ({paramStr})";
}
}
}

0 comments on commit 55c1900

Please sign in to comment.