Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spatial and data seeding: Migration generates files with concrete class (e.g. Point) instead of interface (e.g. IPoint) and do not compile #13747

Closed
divega opened this issue Oct 24, 2018 · 3 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@divega
Copy link
Contributor

divega commented Oct 24, 2018

Repro steps:

  1. Create project using IPoint, e.g.:
using System;
using System.Linq;
using GeoAPI.Geometries;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NetTopologySuite;

namespace Demos
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            using (var context = new SensorContext())
            {
                Console.ReadLine();
            }

            using (var context = new SensorContext())
            {
                var currentLocation = context.GeometryFactory.CreatePoint(new Coordinate(0, 0));

                // Step 2: To use tag in follow query add following code after context.Measurements
                // .TagWith("This is my spatial query!")
                var nearestMesurements =
                    (from m in context.Measurements.TagWith("This is my spatial query!")
                    where m.Location.Distance(currentLocation) < 2.5
                    orderby m.Location.Distance(currentLocation) descending
                    select m).Take(5);

                foreach (var m in nearestMesurements)
                {
                    Console.WriteLine($"A temperature of {m.Temperature} was detected on {m.Time} at {m.Location}.");
                }
            }
        }
    }

    public class SensorContext : DbContext
    {
        private static readonly IGeometryFactory _geometryFactory = 
            NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);

        private static readonly ILoggerFactory _loggerFactory = new LoggerFactory()
            .AddConsole((s, l) => l == LogLevel.Information && s.EndsWith("Command"));

        public IGeometryFactory GeometryFactory => _geometryFactory;

        public DbSet<Measurement> Measurements { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Demo.Spatial;Trusted_Connection=True;ConnectRetryCount=0",
                        sqlOptions => sqlOptions.UseNetTopologySuite())
                .UseLoggerFactory(_loggerFactory);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Measurement>().HasData(
              new Measurement {Id = 1, Time = DateTime.Now, Location = GeometryFactory.CreatePoint(new Coordinate(0, 0)), Temperature = 0.0 },
              new Measurement {Id = 2, Time = DateTime.Now, Location = GeometryFactory.CreatePoint(new Coordinate(1, 1)), Temperature = 0.1 },
              new Measurement {Id = 3, Time = DateTime.Now, Location = GeometryFactory.CreatePoint(new Coordinate(1, 2)), Temperature = 0.2 },
              new Measurement {Id = 4, Time = DateTime.Now, Location = GeometryFactory.CreatePoint(new Coordinate(2, 1)), Temperature = 0.3 },
              new Measurement {Id = 5, Time = DateTime.Now, Location = GeometryFactory.CreatePoint(new Coordinate(2, 2)), Temperature = 0.4 });
        }

    }

    public class Measurement
    {
        public int Id { get; set; }
        public DateTime Time { get; set; }
        public IPoint Location { get; set; }
        public double Temperature { get; set; }
    }
}
  1. Add a migration
  2. Try to build

Expected:
Only the GeoAPI.Geometries namespace should be imported in all generated files, and the type IPoint should be used for any necessary casts.

Actual:
All files use Point instead of IPoint. The migration file imports the NetTopologySuite.Geometries (probably incorrectly) which means type Point does resolve, but .Designer and snapshot files only import the GeoAPI.Geometries (correctly) but and incorrectly use Point instead of IPoint.

@ajcvickers ajcvickers added this to the 2.2.0 milestone Oct 26, 2018
@ajcvickers
Copy link
Member

@bricelam @divega I investigated this and the root cause is two fold:

  • The interface type used for the property is not always available, most notably in HasData where type mapping is for the concrete type used in the HasData call.
  • The type used in the final cast of the literal expression is not always a type for which there is already a using directive. This is coupled to there being currently no way to generate a using based on the types used in this Expression.

Ideally, the best way to fix this is to allow the literal generation to influence the using statements generated. This would also stop us from fully-qualifying other types here, such as the factory. However, this looks non-trivial to do and probably not something we should do for 2.2. For 2.2, we can just start fully qualifying the cast.

I'll send a PR for the latter, but we can discuss tomorrow.

@divega
Copy link
Contributor Author

divega commented Oct 29, 2018

@ajcvickers sounds reasonable.

@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Oct 29, 2018
ajcvickers added a commit that referenced this issue Oct 29, 2018
@ajcvickers
Copy link
Member

See also #13799

@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

3 participants