Skip to content

FromSql client side projection including additional data #1885

Closed
@matt-psaltis

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

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions