I am using EF Core v5.0.5 with a code-first approach. Within my domain classes I do have some which contains fields of LocalDate type (https://nodatime.org/2.2.x/api/NodaTime.LocalDate.html), like:
public class TimeSlot
{
public Guid Id { get; set; }
public LocalDate StartDate { get; set; }
public TimeSlot(LocalDate startDate)
{
StartDate = startDate;
}
}
I am completely fine to generate the initial migration with the very basic command:
dotnet ef migrations add InitalMigration
And then the migration can be applied so the database is correctly and successfully created.
However, once I do try to add a new field of the same type (for example LocalDate EndDate), I am getting the following error:
System.InvalidOperationException: Cannot scaffold C# literals of type 'NodaTime.LocalDate'. The provider should implement CoreTypeMapping.GenerateCodeLiteral to support using it at design time.
at Microsoft.EntityFrameworkCore.Design.Internal.CSharpHelper.UnknownLiteral(Object value)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationOperationGenerator.Generate(AddColumnOperation operation, IndentedStringBuilder builder)
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3[T0,T1,T2](CallSite site, T0 arg0, T1 arg1, T2 arg2)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationOperationGenerator.Generate(String builderName, IReadOnlyList1 operations, IndentedStringBuilder builder) at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGenerator.GenerateMigration(String migrationNamespace, String migrationName, IReadOnlyList1 upOperations, IReadOnlyList1 downOperations) at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language) at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_01.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Cannot scaffold C# literals of type 'NodaTime.LocalDate'. The provider should implement CoreTypeMapping.GenerateCodeLiteral to support using it at design time.
This message leaves me completely clueless since a moment ago EF Core was completely fine to generate a proper migration. I would appreciate any cue why it is working the way we can see.
I made a project with asp.net core 5 and Identity and PostgreSql for database,
when i change user id to int, then can't run Add-Migration and show this error below but when use SqlServer haven't any error and run correctly.
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
at Npgsql.EntityFrameworkCore.PostgreSQL.Design.Internal.NpgsqlAnnotationCodeGenerator.GenerateValueGenerationStrategy(IDictionary`2 annotations, Boolean onModel)
at Npgsql.EntityFrameworkCore.PostgreSQL.Design.Internal.NpgsqlAnnotationCodeGenerator.GenerateFluentApiCalls(IProperty property, IDictionary`2 annotations)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GeneratePropertyAnnotations(IProperty property, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateProperty(String builderName, IProperty property, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateProperties(String builderName, IEnumerable`1 properties, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityType(String builderName, IEntityType entityType, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityTypes(String builderName, IReadOnlyList`1 entityTypes, IndentedStringBuilder stringBuilder)
at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGenerator.GenerateMetadata(String migrationNamespace, Type contextType, String migrationName, String migrationId, IModel targetModel)
at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Specified argument was out of the range of valid values.
My code changes for change user id to int is:
in Startup:
services.AddIdentity<MyIdentityUser, IdentityRole<int>>()
.AddEntityFrameworkStores<MyAppContext>()
.AddDefaultTokenProviders();
in data context:
public class MyAppContext : IdentityDbContext<MyIdentityUser, IdentityRole<int>, int>
...
public class MyIdentityUser:IdentityUser<int>
{}
What is the problem?
I want make this change for improve Database performance in queries because I think query for integer is faster than default user id which is Guid(which is long string instead integer), is this correct?
I've created a sample project which uses the following packages -
GraphQL
GraphQL.EntityFramework
System.Linq.Dynamic.Core
The idea here is to translate the selection done in the GraphQL query and pass that onto EntityFramework in order not to over-fetch columns that are not asked for in the query. For this I'm passing the Select expression in the form on a string using System.Linq.Dynamic.Core. I've seen that there is an issue on the EntityFramework github repo for fetching navigation properties which states that include is a must, as discussed here. Following that I've included the navigation properties needed before making the Select but for some reason it complains with the following error -
GraphQL.ExecutionError: Error trying to resolve customers.
---> System.InvalidOperationException: Include has been used on non entity queryable.
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.ProcessInclude(NavigationExpansionExpression source, Expression expression, Boolean thenInclude)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.Expand(Expression query)
at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at GraphQL.EntityFramework.EfGraphQLService`1.<>c__DisplayClass26_0`2.<<BuildQueryField>b__0>d.MoveNext() in C:\\projects\\graphql-entityframework\\src\\GraphQL.EntityFramework\\GraphApi\\EfGraphQLService_Queryable.cs:line 130
at GraphQL.Instrumentation.MiddlewareResolver.Resolve(ResolveFieldContext context)
at GraphQL.Execution.ExecutionStrategy.ExecuteNodeAsync(ExecutionContext context, ExecutionNode node)
and here is the piece of code that is failing
public class QueryTest : QueryGraphType<TestDBContext>
{
public QueryTest(IEfGraphQLService<TestDBContext> graphQlService) :
base(graphQlService)
{
Name = "Query";
AddQueryField(
name: "customers",
// the next line is failing
resolve: context => context.DbContext.Customers.Include(x => x.Orders).Select<Customer>(GetSelect(context.SubFields))
);
AddQueryField(
name: "orders",
resolve: context => context.DbContext.Orders.Include(x => x.Customer).Select<Order>(GetSelect(context.SubFields))
);
}
private string GetSelect(IDictionary<string, Field> subfields) => $"new({string.Join(",", GetSelectedColumns(subfields))})";
private IEnumerable<string> GetSelectedColumns(IDictionary<string, Field> subfields)
{
foreach (var item in subfields)
{
if (item.Value.SelectionSet.Children.Count() > 0)
{
continue;
}
yield return item.Key;
}
}
}
when I issue the following GraphQL query
query {
customers {
customerName
orders {
orderID
orderDate
}
}
}
The full code example is hosted on github instead of pasting it here as it will be too long to read. Any help would be highly appreciated.
Did you try this project : https://github.com/StefH/GraphQL.EntityFrameworkCore.DynamicLinq ?
With this project you can easily expose all properties from the EF Entities as searchable fields on the GraphQL query.
For example, see https://github.com/StefH/GraphQL.EntityFrameworkCore.DynamicLinq/tree/master/examples/MyHotel
I have a set up where I have
services.AddIdentity<AppUser, AppRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddUserManager<userManage>()
.AddDefaultTokenProviders();
where AppUser and AppRole is used, but it seems to fail because of that. I keep getting
ArgumentNullException: Value cannot be null. Parameter name: type for the claims at System.Security.Claims.Claim..ctor
after
Microsoft.AspNetCore.Identity.IdentityUserClaim1.ToClaim()
Whole log at the bottom
Everything was working before I introduced the extension for the IdentityUser and IdentityRole
for the IDS4 set up I have:
services.AddIdentityServer(options => {
options.UserInteraction.LoginUrl = "/Account/Login";
})
.AddSigningCredential(new X509Certificate2(Path.Combine(".", "certs"
, "IdentityServer4Auth.pfx")))
.AddAspNetIdentity<AppUser>()
.AddConfigurationStore(options => {
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connection_string, sql => sql.MigrationsAssembly(migrations_assembly));
})
.AddOperationalStore(options => {
//options.DefaultSchema = "token";
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connection_string, sql => sql.MigrationsAssembly(migrations_assembly));
})
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddJwtBearerClientAuthentication()
.AddProfileService<IdentityProfileService>();
that was working fine, but the switch from
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{ })
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddDistributedMemoryCache();
to
services.AddIdentity<AppUser, AppRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddUserManager<userManage>()
.AddDefaultTokenProviders();
and that kills it now. I know it works as far as the AppUser, AppRole, and userManage are set up because they the same set up used in many of my apps, but as soon as it is mix with the IDS4 it is now failing. When it was working i had extended the IdentityUser
public class ApplicationUser : IdentityUser {}
The was working too, it was when I mixed the 2 apps together, so both had the AppUser, AppRole, and userManage, is when it went bad. I will put the models below
Side note too, I have followed the logs, and what is killing me here is the query run in the DB is correct. When I run it I see no nulls for any type values. I have even scrubbed the DB for any nulls in any of the claim areas, like the roles or user level just to be safe. I have put a break point on the area that causes the fault,
var signin_result = await _signInManager.PasswordSignInAsync(_user, test, model.RememberMe, false);
which when I look at the _user I see that it has the security stamp and all values correctly filled
it is on the user claims
SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId]
FROM [AspNetUserClaims] AS [uc]
WHERE [uc].[UserId] = #__user_Id_0
but I don't see where the issue is when that returns nothing with a null
the log
2018-10-08 13:17:47.164 -07:00 [Information] Entity Framework Core "2.1.4-rtm-31024" initialized '"ApplicationDbContext"' using provider '"Microsoft.EntityFrameworkCore.SqlServer"' with options: "SensitiveDataLoggingEnabled "
2018-10-08 13:17:47.189 -07:00 [Information] Executed DbCommand ("1"ms) [Parameters=["#__user_Id_0='11325643' (Size = 450)"], CommandType='Text', CommandTimeout='30']"
""SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId]
FROM [AspNetUserClaims] AS [uc]
WHERE [uc].[UserId] = #__user_Id_0"
2018-10-08 13:17:47.370 -07:00 [Error] An exception occurred in the database while iterating the results of a query for context type '"test.app.Data.ApplicationDbContext"'."
""System.ArgumentNullException: Value cannot be null.
Parameter name: type
at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue)
at System.Security.Claims.Claim..ctor(String type, String value)
at Microsoft.AspNetCore.Identity.IdentityUserClaim`1.ToClaim()
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.IShaper<TOut>.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.BufferlessMoveNext(DbContext _, Boolean buffer, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.MoveNext(CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)"
System.ArgumentNullException: Value cannot be null.
Parameter name: type
at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue)
at System.Security.Claims.Claim..ctor(String type, String value)
at Microsoft.AspNetCore.Identity.IdentityUserClaim`1.ToClaim()
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.IShaper<TOut>.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.BufferlessMoveNext(DbContext _, Boolean buffer, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.MoveNext(CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)
2018-10-08 13:17:48.680 -07:00 [Information] Executed action "WSU.Sso.Controllers.AccountController.Login (test.app)" in 2022.4589ms
The Models, and set up (note in the none IDS4 app these are working just fine)
public class AppUser : IdentityUser {}
public class AppRole : IdentityRole {}
public class AppUserClaim : IdentityUserClaim<string> {}
public class AppUserRole : IdentityUserRole<string> {}
public class AppRoleClaims : IdentityRoleClaim<string> {}
public partial class CoreDbContext : IdentityDbContext
<
AppUser, // TUser
AppRole, // TRole
string, // TKey
AppUserClaim, // TUserClaim
AppUserRole, // TUserRole,
IdentityUserLogin<string>, // TUserLogin
AppRoleClaims, // TRoleClaim
IdentityUserToken<string> // TUserToken
>//, ICoreDbContext
{
//etc..
}
Update
I believe the issue is here, https://github.com/IdentityServer/IdentityServer4.AspNetIdentity/blob/dev/src/UserClaimsFactory.cs where UserManager<TUser> userManager needs to be userManage because I extended that. I am guessing I need to role my own it seems?
Update 2
Turns out, after removing the userManage extending UserManager<TUser> that it still fails with
System.Security.Claims.Claim..ctor(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject, string propertyKey, string propertyValue)
System.Security.Claims.Claim..ctor(string type, string value)
Microsoft.AspNetCore.Identity.IdentityUserClaim.ToClaim()
There was hope that simplifying it would be the anwser so i didn't have to rewrite the .AddAspNetIdentity<AppUser>() but that didn't work. It is clear that it is not something that comes from the DB that is null, but must be something added that it's value is null. I can't tell what, just that it must be between the Microsoft.AspNetCore.Identity.IdentityUserClaim<TKey>.ToClaim() and the IdentityServer4.AspNetIdentity.UserClaimsFactory<TUser>.CreateAsync(TUser user) in UserClaimsFactory.cs ... What I can say for sure is that in https://github.com/IdentityServer/IdentityServer4.AspNetIdentity/blob/dev/src/UserClaimsFactory.cs all of the parts that is is trying to set is verifaied in the DB as not null.
It is also worth nothing that the IDS4 was working before I added the the custom role. I am not 100% sure that is not still in play here.
Side note
So I am left wondering, as i rule things out, if it is the name of the ID that is the issue here. In the update the tables for AspNetUser has the table set as user_id not Id (Microsoft Owin Security - Claims Constructor Value cannot be null is what is leading me to think about this). With that said, I believe there is nothing wrong with the set up, here is what I have in my OnModelCreating(ModelBuilder builder),
builder.Entity<AppUser>().Property(p => p.Id).HasColumnName("user_id");
We have not had any issue up to this point on using it, but I'm running down all differences in the user that would be an issue root.
Update 3
after stepping through public class IdentityUserClaim<TKey> where TKey : IEquatable<TKey> and putting a break point on Claim ToClaim() the type is the null. Which is a duh on the log, but I can't seem to back track in the call stack where that roots from. My question sits at, if the DB query returns a proper set of types and values, then why is there a null type and value set to process first? The very first time that breakpoint is hit, the type is null.
UPDATE 4 major stop
after hitting every break point I am now stuck and wounder if i am hitting a bug here. I get in to the UserManager and follow the stack and can see that the main claims are there and ok.
And then the next part is to run the claims store which executes the query above, and at that point is when it fails. I can't see why. I run the query in SQL Manager and it is ok, not one NULL.
Does anyone see what is going on? I am at a loss at this moment.
UPDATE 5 - narrowing down
So failing to notice the locals when i hit the claim being set as null, I see that the values I want are in the scope of this
The issue here is now how is the scope off and I have the values wanted in the wrong place
The issue took a bit to walk around, but it is clear now why there was a failing. AppUserClaim is the real issue. It was hard to tell, and over looking the locals at that step, is why I had to go the long way around here.
The extended IdentityUserClaim<string> I had was
public class AppUserClaim : IdentityUserClaim<string>
{
public int Id { get; set; }
/// <summary>
/// Gets or sets the primary key of the user associated with this claim.
/// </summary>
public virtual string UserId { get; set; }
public virtual AppUser user { get; set; }
/// <summary>
/// Gets or sets the claim type for this claim.
/// </summary>
public virtual string ClaimType { get; set; }
/// <summary>
/// Gets or sets the claim value for this claim.
/// </summary>
public virtual string ClaimValue { get; set; }
}
But the properties of ClaimType and ClaimValue where not needing to be overwrote. Once I had done that, it set the values where they where out of scope for the methods. Changing the model to be
public class AppUserClaim : IdentityUserClaim<string> {
public virtual AppUser user { get; set; } // note this is the reason why i had to extend
}
Solves the issue. It did't appear in the other apps because claims where set from the SSO, so that method was always skipped.
Lessons for me to remember, always make sure you look at the locals when stepping through. It took me stepping away for a day before I saw the duh moment.
In my application (database-first) the primary keys are always created by client, not by the underlying database.
In Entity Framework v4 each Entity had it's EntityKey property that could be set manually.
However, I can't find it anymore in EF6?
Is there any specific reason why?
I don't want to call ctx.SaveChanges() only to have an Entity's key set as this means a call to the database.
I'm also wondering why ObjectContext.CreateEntityKey is gone?!
If You're using POCO's - here's a sample how it could be done
public class ChronosItem
{
[Column, Key, Required, MaxLength(26), DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }
....
In case You cant adjust Your entities
override the "OnModelCreating" method on Your context.. like so..
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ChronosItem >()
.HasKey(p => p.Id)
.Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);