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

Integration with EFCore.NetTopologySuite #388

Open
MitchellW-DWL opened this issue Mar 21, 2024 · 1 comment
Open

Integration with EFCore.NetTopologySuite #388

MitchellW-DWL opened this issue Mar 21, 2024 · 1 comment

Comments

@MitchellW-DWL
Copy link

MitchellW-DWL commented Mar 21, 2024

I was led to do this by #49 saying to open new if still existing

I've followed all steps in the above adding the following mappings:

Linq2Db Config

        LinqToDBForEFTools.Initialize();
        DataConnection.TurnTraceSwitchOn();
        DataConnection.WriteTraceLine = (message, displayName, traceLevel) =>
        {
            Console.WriteLine($"{displayName} {message}");
        };
        
        var mapping = MappingSchema.Default;
        var geoWriter = new SqlServerBytesWriter();
        mapping.SetConverter<Point, DataParameter>(g =>
        {
            var x = geoWriter.Write(g);
            return new DataParameter("p", x, DataType.Udt);
        });
        
        var reader = new SqlServerBytesReader();
        mapping.SetConverter<byte[], Geometry>((sqlGeomInBytes) => 
        {
            var geometry = reader.Read(sqlGeomInBytes);
            return geometry;
        });

And I have the following code I'm trying to run:

Query

        using (var dc = context.CreateLinqToDBContext())
        {
            await using var table = await dc.CreateTempTableAsync(
                stations, 
                tableName: Guid.NewGuid().ToString(),
                databaseName: "foo", 
                cancellationToken: cancellationToken);
            var targetTable = dc.GetTable<StationEntity>();
            
            var x = await targetTable.Merge()
                .Using(table)
                .On((tgt, src) => tgt.Location.Distance(src.Location) < 10)
                .InsertWhenNotMatched(station => station)
                .UpdateWhenMatched((tgt, src) => src)
                .MergeAsync(cancellationToken);
        }

Note: context here is my injected DbContext instance

But when executing this I get SQL Error

Stack Trace

Exception: Microsoft.Data.SqlClient.SqlException
Message  : 'STDistance' is not a recognized built-in function name.
   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.SqlCommand.InternalEndExecuteNonQuery(IAsyncResult asyncResult, Boolean isInternal, String endMethod)
   at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult)
   at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult asyncResult)
   at Microsoft.Data.SqlClient.SqlCommand.<>c.<InternalExecuteNonQueryAsync>b__210_1(IAsyncResult result)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location ---
   at LinqToDB.Data.DataConnection.ExecuteNonQueryAsync(CancellationToken cancellationToken)
   at LinqToDB.Data.DataConnection.ExecuteNonQueryAsync(CancellationToken cancellationToken)
   at LinqToDB.Data.DataConnection.ExecuteNonQueryDataAsync(CancellationToken cancellationToken)
   at LinqToDB.Data.DataConnection.ExecuteNonQueryDataAsync(CancellationToken cancellationToken)

Which is correct, I can see ON (STDistance([Source].[Location]) < 10) given as the predicate in outputted query _(It should be [Target].[Location].STDistance([Source].[Location]) but using these operations from Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite in other more simpler queries behaves as expected

await context.Stations.Where(station <= station.Distance(somePoint) < 100)
    .ToListAsync()

(I can see that issue #49 was having the exact same with another function at the end of the thread)

@MitchellW-DWL MitchellW-DWL changed the title Integration with EFCore.NetToplog Integration with EFCore.NetTopologySuite Mar 21, 2024
@MitchellW-DWL
Copy link
Author

Just FYI I've managed to get around this for now by defining the following:

    [Sql.Expression("{0}.STDistance({1})", ServerSideOnly = true)]
    public static double DistanceTo(this Point p1, Point p2)
        => throw new NotImplementedException("Method cannot be executed during runtime");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant