Entity Framework Core return few selects

.net-core c# entity-framework entity-framework-core

Question

How to return few selects from EF Core (SQL Server database)?

I tried next example, but got an error:

No mapping to a relational type can be found for the CLR type 'Test1'

The error occurs on this line:

var valueBufferFactory = set
    .GetService<IRelationalValueBufferFactoryFactory>()
    .Create(new[] { typeof(T) }, null);

Here's the relevant code:

public void Test()
{
    using (var cnn = _context.Database.GetDbConnection())
    {
        var cmm = cnn.CreateCommand();
        cmm.CommandType = System.Data.CommandType.Text;
        cmm.CommandText = "select id, name, code from dbo.Test1; select id, name, singleChoice from dbo.Test2";
        cmm.Connection = cnn;
        cnn.Open();
        using (var reader = cmm.ExecuteReader())
        {
            var answers = _context.Test1.Translate(reader);
            reader.NextResult();
            var questions = _context.Test2.Translate(reader);
        }
    }
}

public static List<T> Translate<T>(this DbSet<T> set, DbDataReader reader) where T : class
{
    var entityList = new List<T>();
    if (reader == null || reader.HasRows == false) return entityList;
    var entityType = set.GetService<Microsoft.EntityFrameworkCore.Metadata.IModel>().FindEntityType(typeof(T));
    var valueBufferParameter = Expression.Parameter(typeof(ValueBuffer));
    var entityMaterializerSource = set.GetService<IEntityMaterializerSource>();
    var valueBufferFactory = set.GetService<IRelationalValueBufferFactoryFactory>().Create(new[] { typeof(T) }, null);

    var stateManager = set.GetService<IStateManager>() as StateManager;
    Func<ValueBuffer, T> materializer = Expression
        .Lambda<Func<ValueBuffer, T>>(entityMaterializerSource.CreateMaterializeExpression(entityType, valueBufferParameter), valueBufferParameter)
        .Compile();
    stateManager.BeginTrackingQuery();
    while (reader.Read())
    {
        ValueBuffer valueBuffer = valueBufferFactory.Create(reader);
        var entity = materializer.Invoke(valueBuffer);
        var entry = stateManager.StartTrackingFromQuery(entityType, entity, valueBuffer, null);
        entityList.Add((T)entry.Entity);
    }
    return entityList;
}
1
2
11/30/2018 11:15:19 AM

Accepted Answer

You are using a lot of EF Core internal stuff, so keep in mind that any part of this code may (and probably will) break in the future EF Core versions (even now I'm getting warning that Create method used is obsolete).

Anyway, the way it is now, the problem is the first argument to Create - you are passing new[] { typeof(T) } (the type of the entity) while it expects an array containing the CLR types of the properties to be mapped from the reader.

Hence the following should work:

var valueBufferFactory = set.GetService<IRelationalValueBufferFactoryFactory>()
    .Create(entityType.GetProperties().Select(p => p.ClrType).ToArray(), null);
2
11/30/2018 9:54:49 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow