FromSql client side projection including additional data #1885
Description
I'm trying to formulate queries based on information returned from a FromSql call. I would like to project the returned information into the model for the association including information that was present at the time the association was built into the MappingSchema.
The example below demonstrates the type of query. I'm using one of the existing Linq2db tests running as SqlCe to demonstrate this so some of the stackframes will reference SqlCe. Actual scenario is against MSSQL 2017.
[Test]
public void TestGenericAssociationRuntime([DataSources(ProviderName.Access, TestProvName.AllSQLite)] string context)
{
var ms = new MappingSchema();
var mb = ms.GetFluentMappingBuilder();
var values = new[] { 1, 5 };
mb.Entity<User>()
.Association(t => t.Data, (t, db) => db.FromSql<Model>("SELECT 'Testing' AS Data")
.Where(x => t.Id == t.Id) // Necessary so that AssociationParentJoin is not null
.Select(x => new Testing
{
Ids = values,
Value = x.Data
})
);
using (var db = GetDataContext(context, ms))
using (var u = db.CreateLocalTable<User>())
{
u.Insert(() => new User { Id = 1 });
u.Insert(() => new User { Id = 2 });
var q =
from t in db.GetTable<User>()
select t.Data;
var list = q.ToList();
}
}
public class User
{
public int Id { get; set; }
public Testing Data { get; set; }
}
public class Testing
{
[Column]
// Test scenario 2: [NotColumn]
public int[] Ids { get; set; }
public string Value { get; set; }
}
There's a couple of different approaches I've tried each with their exception:
Scenario 1: Testing.Ids (Column attribute):
When I use the Column attribute on the Testing.Ids property, I receive the following exception:
No mapping exists from DbType System.Int32[] to a known SqlCeType.
at System.Data.SqlServerCe.SqlCeType.FromClrType(Object value)
at System.Data.SqlServerCe.SqlCeParameter.set_Value(Object value)
at LinqToDB.DataProvider.DataProviderBase.SetParameter(IDbDataParameter parameter, String name, DbDataType dataType, Object value) in C:\Development\Sandbox\Linq2db-scalar-fromsql\Source\LinqToDB\DataProvider\DataProviderBase.cs:line 327
Scenario 2: Testing.Ids (NotColumn attribute):
When I remove the Column attribute from the Testing.Ids property or use the NotColumn attribute, I receive an index out of range error because the Ids property is included into the SqlInfo of the Testing class.
Exception message:
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index'
Stack trace:
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.Collections.Generic.List`1.get_Item(Int32 index)
at LinqToDB.Linq.Builder.TableBuilder.TableContext.<>c__DisplayClass46_0.<BuildDefaultConstructor>b__2(<>f__AnonymousType85`2 idx) in C:\Development\Sandbox\Linq2db-scalar-fromsql\Source\LinqToDB\Linq\Builder\TableBuilder.TableContext.cs:line 336
from idx in index.Select((n,i) => new { n, i })
where idx.n >= 0
let cd = entityDescriptor.Columns[idx.i] // Here
BuildDefaultConstructor method's index parameter receives an index of length 2, however the EntityDescriptor only has the Value column due to the NotColumn attribute.
Scenario 3: Constructor argument:
.Select(x => new Testing(values)
{
Value = x.Data
})
Current code flow requires default constructor
Environment details
linq2db version: 2.9.0
Database Server: MSSQL
Database Provider: SqlClient
Operating system: Win10/2019
.NET Framework: .net core 2.2