I am trying to read items from a CosmosDb database. The code below fails with the error "Invalid cast from 'System.Int32' to 'CosmosDbDemo.Model.OfferStatus'".
// Referenced NuGet packages:
// - Microsoft.EntityFrameworkCore 3.1.2
// - Microsoft.EntityFrameworkCore.Cosmos 3.1.2
// - Microsoft.Extensions.DependencyInjection 3.1.2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace CosmosDbDemo
{
#region CosmosDb parameters
// Define here your CosmosDb database connection
class CosmosDbParameters
{
public const string AccountEndPoint = "{YOUR-ACCOUNT-ENDPOINT-HERE}";
public const string AccountKey = "{YOUR-ACCOUNT-KEY-HERE}";
public const string DbName = "DemoIssues";
public const string DbContainer = "Offers";
}
#endregion
class Program
{
static async Task Main( string[] args )
{
// Configure services
var serviceProvider =
new ServiceCollection()
.AddDbContext<OfferContext>(
options => options.UseCosmos( CosmosDbParameters.AccountEndPoint, CosmosDbParameters.AccountKey, CosmosDbParameters.DbName ) )
.BuildServiceProvider();
using var ctx = serviceProvider.GetService<OfferContext>();
// Ensure database has been properly created.
ctx.Database.EnsureCreated();
// Insert some items. A future query will try to retrieve only some of them.
await AddItems( ctx );
// Query for some items. Reproduces the issue with enums
// serialized as text.
await QueryUsingEFWithServerEvaluation( ctx );
// Query for items, but first pull all items to the client
// and then execute a filtering operation. This one works,
// but it's not acceptable.
await QueryUsingEFWithClientEvaluation( ctx );
}
private static async Task QueryUsingEFWithClientEvaluation( OfferContext ctx )
{
try
{
var offers = await ctx
.Offers
.ToListAsync();
offers = offers.Where( _ => _.Status == OfferStatus.Created ).ToList();
Console.WriteLine( $"With client evaluation: {offers.Count} offers found" );
}
catch( Exception ex )
{
Console.Write( ex );
}
}
private static async Task QueryUsingEFWithServerEvaluation( OfferContext ctx )
{
try
{
// The call below fails with exception
// "Invalid cast from 'System.Int32' to 'CosmosDbDemo.Model.OfferStatus'"
var offers = await ctx
.Offers
.Where( _ => _.Status == OfferStatus.Created )
.ToListAsync();
Console.WriteLine( $"With server evaluation: {offers.Count} offers found" );
}
catch( Exception ex )
{
Console.Write( ex );
}
}
private static async Task AddItems( OfferContext ctx )
{
var offer = BuildOffer( "Acme Offer 1", 14 );
ctx.Add( offer );
offer = BuildOffer( "Acme Offer 2", 30 );
ctx.Add( offer );
offer = BuildOffer( "Coyote Ugly Super Offer 1", 25 );
ctx.Add( offer );
offer = BuildOffer( "Sloth Supercars Offer 14", 10 );
ctx.Add( offer );
await ctx.SaveChangesAsync();
}
private static Offer BuildOffer( string name, int valabilityInDays )
{
var result = new Offer
{
Id = Guid.NewGuid(),
Name = name,
ExpirationDateUtc = DateTime.UtcNow.Date.AddDays( valabilityInDays ),
Status = OfferStatus.Created
};
return result;
}
}
class Offer
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime ExpirationDateUtc { get; set; }
public OfferStatus Status { get; set; }
}
enum OfferStatus
{
Created = 0,
Approved = 1,
Accepted = 2,
Declined = 3
}
class OfferContext : DbContext
{
public OfferContext( DbContextOptions<OfferContext> options ) : base( options )
{
}
public DbSet<Offer> Offers { get; set; }
protected override void OnModelCreating( ModelBuilder modelBuilder )
{
modelBuilder.HasDefaultContainer( CosmosDbParameters.DbContainer );
modelBuilder.Entity<Offer>().HasPartitionKey( _ => _.Id );
modelBuilder.Entity<Offer>().Property( _ => _.Id )
.HasConversion( _ => _.ToString( "B" ), _ => Guid.Parse( _ ) );
modelBuilder.Entity<Offer>().Property( _ => _.Status )
.HasConversion( _ => _.ToString(), _ => (OfferStatus)Enum.Parse( typeof( OfferStatus ), _ ) );
}
}
}
Exception information:
System.InvalidCastException: Invalid cast from 'System.Int32' to 'CosmosDbDemo.OfferStatus'.
at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
at System.Int32.System.IConvertible.ToType(Type type, IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType)
at Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter`2.Sanitize[T](Object value)
at Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter`2.<>c__DisplayClass3_0`2.<SanitizeConverter>b__0(Object v)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.QuerySqlGenerator.GenerateJToken(Object value, CoreTypeMapping typeMapping)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.QuerySqlGenerator.VisitSqlConstant(SqlConstantExpression sqlConstantExpression)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.SqlExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.QuerySqlGenerator.VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.SqlExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.QuerySqlGenerator.VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.SqlExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.QuerySqlGenerator.VisitSelect(SelectExpression selectExpression)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.SqlExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.QuerySqlGenerator.GetSqlQuery(SelectExpression selectExpression, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.CosmosShapedQueryCompilingExpressionVisitor.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at CosmosDbDemo.Program.QueryUsingEFWithServerEvaluation(OfferContext ctx) in D:\Work\CosmosDbDemo\Program.cs:line 134
Further technical details
EF Core version: 3.1.2
Database provider: Microsoft.EntityFrameworkCore.Cosmos
Target framework: .NET Core 3.1
Operating system: Windows 10.0.18363.720
IDE: Visual Studio 2019 16.5.0
I am trying to read items from a CosmosDb database. The code below fails with the error "Invalid cast from 'System.Int32' to 'CosmosDbDemo.Model.OfferStatus'".
Further technical details
EF Core version: 3.1.2
Database provider: Microsoft.EntityFrameworkCore.Cosmos
Target framework: .NET Core 3.1
Operating system: Windows 10.0.18363.720
IDE: Visual Studio 2019 16.5.0