diff --git a/src/CommonAssemblyInfo.cs b/src/CommonAssemblyInfo.cs index 1a7f45e..a2079be 100644 --- a/src/CommonAssemblyInfo.cs +++ b/src/CommonAssemblyInfo.cs @@ -16,6 +16,6 @@ [assembly: NeutralResourcesLanguage("en", UltimateResourceFallbackLocation.MainAssembly)] // The following version attributes get rewritten by GitVersion as part of the build -[assembly: AssemblyVersion("3.1.0")] -[assembly: AssemblyFileVersion("3.1.0")] -[assembly: AssemblyInformationalVersion("3.1.0")] +[assembly: AssemblyVersion("3.1.1")] +[assembly: AssemblyFileVersion("3.1.1")] +[assembly: AssemblyInformationalVersion("3.1.1")] diff --git a/src/EntityFramework5.Npgsql/EntityFramework5.Npgsql.nuspec b/src/EntityFramework5.Npgsql/EntityFramework5.Npgsql.nuspec index 07f54f7..720e73d 100644 --- a/src/EntityFramework5.Npgsql/EntityFramework5.Npgsql.nuspec +++ b/src/EntityFramework5.Npgsql/EntityFramework5.Npgsql.nuspec @@ -3,7 +3,7 @@ EntityFramework5.Npgsql Npgsql for Entity Framework 5 - 3.1.0 + 3.1.1 Shay Rojansky, Emil Lenngren, Francisco Figueiredo Jr., Kenji Uno, Jon Asher, John Cooley, Federico Di Gregorio, Jon Hanna, Chris Morgan, Dave Page, Glen Parker, Brar Piening, Hiroshi Saito Shay Rojansky, Emil Lenngren, Francisco Figueiredo Jr., Kenji Uno https://github.com/npgsql/EntityFramework6.Npgsql/blob/dev/LICENSE.txt diff --git a/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.csproj b/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.csproj index 1d7fb7c..c5b375b 100644 --- a/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.csproj +++ b/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.csproj @@ -69,6 +69,7 @@ + diff --git a/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.nuspec b/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.nuspec index a3aaaf4..9ed906e 100644 --- a/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.nuspec +++ b/src/EntityFramework6.Npgsql/EntityFramework6.Npgsql.nuspec @@ -3,7 +3,7 @@ EntityFramework6.Npgsql Npgsql for Entity Framework 6 - 3.1.0 + 3.1.1 Shay Rojansky, Emil Lenngren, Francisco Figueiredo Jr., Kenji Uno, Jon Asher, John Cooley, Federico Di Gregorio, Jon Hanna, Chris Morgan, Dave Page, Glen Parker, Brar Piening, Hiroshi Saito Shay Rojansky, Emil Lenngren, Francisco Figueiredo Jr., Kenji Uno https://github.com/npgsql/EntityFramework6.Npgsql/blob/dev/LICENSE.txt diff --git a/src/EntityFramework6.Npgsql/NpgsqlProviderManifest.cs b/src/EntityFramework6.Npgsql/NpgsqlProviderManifest.cs index b990f72..e055bce 100644 --- a/src/EntityFramework6.Npgsql/NpgsqlProviderManifest.cs +++ b/src/EntityFramework6.Npgsql/NpgsqlProviderManifest.cs @@ -371,20 +371,15 @@ public override bool SupportsInExpression() } public override ReadOnlyCollection GetStoreFunctions() - { - var functions = new List(); - - functions.AddRange( - typeof(NpgsqlTextFunctions).GetTypeInfo() - .GetMethods(BindingFlags.Public | BindingFlags.Static) - .Select(x => new { Method = x, DbFunction = x.GetCustomAttribute() }) - .Where(x => x.DbFunction != null) - .Select(x => CreateFullTextEdmFunction(x.Method, x.DbFunction))); - - return functions.AsReadOnly(); - } + => new[] { typeof(NpgsqlTextFunctions).GetTypeInfo(), typeof(NpgsqlTypeFunctions) } + .SelectMany(x => x.GetMethods(BindingFlags.Public | BindingFlags.Static)) + .Select(x => new { Method = x, DbFunction = x.GetCustomAttribute() }) + .Where(x => x.DbFunction != null) + .Select(x => CreateComposableEdmFunction(x.Method, x.DbFunction)) + .ToList() + .AsReadOnly(); - private static EdmFunction CreateFullTextEdmFunction(MethodInfo method, DbFunctionAttribute dbFunctionInfo) + static EdmFunction CreateComposableEdmFunction(MethodInfo method, DbFunctionAttribute dbFunctionInfo) { if (method == null) throw new ArgumentNullException("method"); if (dbFunctionInfo == null) throw new ArgumentNullException("dbFunctionInfo"); diff --git a/src/EntityFramework6.Npgsql/NpgsqlTypeFunctions.cs b/src/EntityFramework6.Npgsql/NpgsqlTypeFunctions.cs new file mode 100644 index 0000000..b567668 --- /dev/null +++ b/src/EntityFramework6.Npgsql/NpgsqlTypeFunctions.cs @@ -0,0 +1,20 @@ +using System; +using System.Data.Entity; + +namespace Npgsql +{ + /// + /// Use this class in LINQ queries to emit type manipulation SQL fragments. + /// + public static class NpgsqlTypeFunctions + { + /// + /// Emits an explicit cast for unknown types sent as strings to their correct postgresql type. + /// + [DbFunction("Npgsql", "cast")] + public static string Cast(string unknownTypeValue, string postgresTypeName) + { + throw new NotSupportedException(); + } + } +} \ No newline at end of file diff --git a/src/EntityFramework6.Npgsql/SqlGenerators/SqlBaseGenerator.cs b/src/EntityFramework6.Npgsql/SqlGenerators/SqlBaseGenerator.cs index dd6435e..81dfcbd 100644 --- a/src/EntityFramework6.Npgsql/SqlGenerators/SqlBaseGenerator.cs +++ b/src/EntityFramework6.Npgsql/SqlGenerators/SqlBaseGenerator.cs @@ -333,11 +333,18 @@ private PendingProjectsNode VisitInputWithBinding(DbExpression expression, strin input.Projection = new CommaSeparatedExpression(); DbNewInstanceExpression projection = (DbNewInstanceExpression)exp.Projection; - RowType rowType = projection.ResultType.EdmType as RowType; + RowType rowType = (RowType)projection.ResultType.EdmType; for (int i = 0; i < rowType.Properties.Count && i < projection.Arguments.Count; ++i) { - EdmProperty prop = rowType.Properties[i]; - input.Projection.Arguments.Add(new ColumnExpression(projection.Arguments[i].Accept(this), prop.Name, prop.TypeUsage)); + var prop = rowType.Properties[i]; + var argument = projection.Arguments[i].Accept(this); + var constantArgument = projection.Arguments[i] as DbConstantExpression; + if (constantArgument != null && constantArgument.Value is string) + { + argument = new CastExpression(argument, "varchar"); + } + + input.Projection.Arguments.Add(new ColumnExpression(argument, prop.Name, prop.TypeUsage)); } if (enterScope) LeaveExpression(child); @@ -1210,6 +1217,17 @@ private VisitedExpression VisitFunction(EdmFunction function, IList + { + new Post + { + Content = "Some post content", + Rating = 1, + Title = "Some post Title", + VarbitColumn = varbitVal + } + } + }; + context.Blogs.Add(blog); + context.SaveChanges(); + + Assert.IsTrue( + context.Posts.Select( + p => NpgsqlTypeFunctions.Cast(p.VarbitColumn, "varbit") == varbitVal).First()); + + Assert.IsTrue( + context.Posts.Select( + p => NpgsqlTypeFunctions.Cast(p.VarbitColumn, "varbit") == "10011").First()); + } + } + + [Test] + public void Test_issue_27_select_ef_generated_literals_from_inner_select() + { + using (var context = new BloggingContext(ConnectionString)) + { + context.Database.Log = Console.Out.WriteLine; + + var blog = new Blog { Name = "Hello" }; + context.Users.Add(new Administrator { Blogs = new List { blog } }); + context.Users.Add(new Editor()); + context.SaveChanges(); + + var administrator = context.Users + .Where(x => x is Administrator) // Removing this changes the query to using a UNION which doesn't fail. + .Select( + x => new + { + // causes entity framework to emit a literal discriminator + Computed = x is Administrator + ? "I administrate" + : x is Editor + ? "I edit" + : "Unknown", + // causes an inner select to be emitted thus showing the issue + HasBlog = x.Blogs.Any() + }) + .First(); + + Assert.That(administrator.Computed, Is.EqualTo("I administrate")); + Assert.That(administrator.HasBlog, Is.True); + } + } } } diff --git a/test/EntityFramework6.Npgsql.Tests/Support/EntityFrameworkTestBase.cs b/test/EntityFramework6.Npgsql.Tests/Support/EntityFrameworkTestBase.cs index 366a02f..1fcc3ad 100644 --- a/test/EntityFramework6.Npgsql.Tests/Support/EntityFrameworkTestBase.cs +++ b/test/EntityFramework6.Npgsql.Tests/Support/EntityFrameworkTestBase.cs @@ -104,6 +104,20 @@ public class NoColumnsEntity public int Id { get; set; } } + [Table("Users")] + public abstract class User + { + public int Id { get; set; } + + public IList Blogs { get; set; } + } + + [Table("Editors")] + public class Editor : User { } + + [Table("Administrators")] + public class Administrator : User { } + public class BloggingContext : DbContext { public BloggingContext(string connection) @@ -114,6 +128,9 @@ public BloggingContext(string connection) public DbSet Blogs { get; set; } public DbSet Posts { get; set; } public DbSet NoColumnsEntities { get; set; } + public DbSet Users { get; set; } + public DbSet Editors { get; set; } + public DbSet Administrators { get; set; } [DbFunction("BloggingContext", "ClrStoredAddFunction")] public static int StoredAddFunction(int val1, int val2) @@ -135,6 +152,9 @@ private static DbCompiledModel CreateModel(NpgsqlConnection connection) dbModelBuilder.Entity(); dbModelBuilder.Entity(); dbModelBuilder.Entity(); + dbModelBuilder.Entity(); + dbModelBuilder.Entity(); + dbModelBuilder.Entity(); // Import function var dbModel = dbModelBuilder.Build(connection);