- ABP Framework version: v9.0.4
- UI Type: Angular
- Database System: EF Core SQL Server
- Tiered: Yes
- Exception message and full stack trace:
The entity type 'IdentityUserLogin' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
System.InvalidOperationException: The entity type 'IdentityUserLogin' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger`1 validationLogger)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Volo.Abp.EntityFrameworkCore.AbpDbContextOptionsExtension.<>c__DisplayClass0_0.<ApplyServices>b__1(IServiceProvider provider)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
at Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker()
at Volo.Abp.EntityFrameworkCore.AbpDbContext`1.Initialize(AbpEfCoreDbContextInitializationContext initializationContext)
at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork, String connectionStringName, String connectionString)
at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.GetDbContextAsync()
at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetDbSetAsync()
at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetQueryableAsync()
at Shared.UserNotifications.EfCoreUserNotificationRepository.GetCountAsync(Specification`1 spec, CancellationToken cancellationToken) in C:\Shepherdv2.0\Shepherd2\modules\Shared\src\Shared.EntityFrameworkCore\UserNotifications\EfCoreUserNotificationRepository.cs:line 36
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Shared.UserNotifications.UserNotificationsAppService.GetListAsync(GetUserNotificationsInput input, CancellationToken cancellationToken) in C:\Shepherdv2.0\Shepherd2\modules\Shared\src\Shared.Application\UserNotifications\UserNotificationsAppService.cs:line 36
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at lambda_method5998(Closure, Object)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
- Steps to reproduce the issue:
- We created a modular monolith where we have a Shared Module that includes four domains (for notification) added as
DbSets
toSharedDbContext
andISharedDbContext
, as seen below:
public class Notification : Entity<int>
{
public Notification() { }
public Notification(int notificationTemplateId, string? dataValue, ICollection<UserNotification> userNotifications)
{
NotificationTemplateId = notificationTemplateId;
DataValue = dataValue;
UserNotifications = userNotifications;
}
[ForeignKey(nameof(Template))]
public virtual int NotificationTemplateId { get; set; }
[CanBeNull]
public virtual string? DataValue { get; set; }
public NotificationTemplate Template { get; set; }
public ICollection<UserNotification> UserNotifications { get; set; }
}
public class NotificationTemplate : AggregateRoot<int>
{
public NotificationTemplate(string resourceName, string urlPath, NotificationCode code)
{
Check.NotNull(resourceName, nameof(resourceName));
Check.NotNull(code, nameof(code));
ResourceName = resourceName;
UrlPath = urlPath;
Code = code;
}
[NotNull]
public virtual string ResourceName { get; set; }
[CanBeNull]
public virtual string UrlPath { get; set; }
public virtual NotificationCode Code { get; set; }
public ICollection<Notification> Notifications { get; set; }
}
public class UserDevice : CreationAuditedAggregateRootWithUser<int, IdentityUser>
{
public virtual Guid UserId { get; set; }
public virtual string DeviceId { get; set; }
public UserDevice() { }
public UserDevice(Guid userId, string deviceId)
{
Check.NotNull(userId, nameof(userId));
Check.NotNull(deviceId, nameof(deviceId));
Check.Length(deviceId, nameof(deviceId), UserDeviceConsts.DeviceIdMaxLength, UserDeviceConsts.DeviceIdMinLength);
UserId = userId;
DeviceId = deviceId;
}
}
public class UserNotification : FullAuditedEntityWithUser<int, IdentityUser>
{
public UserNotification() { }
public UserNotification(Guid userId, int? notificationId = null, bool isRead = false)
{
Check.NotNull(userId, nameof(userId));
NotificationId = notificationId;
UserId = userId;
IsRead = isRead;
}
[ForeignKey(nameof(User))]
public virtual Guid UserId { get; set; }
[ForeignKey(nameof(Notification))]
public virtual int? NotificationId { get; set; }
public virtual bool IsRead { get; set; }
public IdentityUser User { get; set; }
public Notification Notification { get; set; }
public void SetAsRead() => IsRead = true;
}
- The configuration for the domains:
public static void ConfigureNotifications(this ModelBuilder builder)
{
if (builder.IsHostDatabase())
{
builder.Entity<Notification>(b =>
{
b.ToTable(SharedDbProperties.DbTablePrefix + "Notifications", SharedDbProperties.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.NotificationTemplateId).HasColumnName(nameof(Notification.NotificationTemplateId));
b.Property(x => x.DataValue).HasColumnName(nameof(Notification.DataValue));
});
}
}
public static void ConfigureNotificationTemplates(this ModelBuilder builder)
{
if (builder.IsHostDatabase())
{
builder.Entity<NotificationTemplate>(b =>
{
b.ToTable(SharedDbProperties.DbTablePrefix + "NotificationTemplates", SharedDbProperties.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.ResourceName).HasColumnName(nameof(NotificationTemplate.ResourceName)).IsRequired();
b.Property(x => x.UrlPath).HasColumnName(nameof(NotificationTemplate.UrlPath));
});
}
}
public static void ConfigureUserDevices(this ModelBuilder builder)
{
if (builder.IsHostDatabase())
{
builder.Entity<UserDevice>(b =>
{
b.ToTable(SharedDbProperties.DbTablePrefix + "UserDevices", SharedDbProperties.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.UserId).HasColumnName(nameof(UserDevice.UserId));
b.Property(x => x.DeviceId).HasColumnName(nameof(UserDevice.DeviceId)).IsRequired().HasMaxLength(UserDeviceConsts.DeviceIdMaxLength);
});
}
}
public static void ConfigureUserNotifications(this ModelBuilder builder)
{
if (builder.IsHostDatabase())
{
builder.Entity<UserNotification>(b =>
{
b.ToTable(SharedDbProperties.DbTablePrefix + "UserNotifications", SharedDbProperties.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.UserId).HasColumnName(nameof(UserNotification.UserId));
b.Property(x => x.NotificationId).HasColumnName(nameof(UserNotification.NotificationId));
b.Property(x => x.IsRead).HasColumnName(nameof(UserNotification.IsRead));
b.HasOne(x => x.Notification).WithMany(x => x.UserNotifications).HasForeignKey(x => x.NotificationId);
});
}
}
- We have a SeedContributor for NotificationTemplate:
public class NotificationTemplateDataSeedContributor : IDataSeedContributor, ITransientDependency
{
private readonly INotificationTemplateRepository _notificationTemplateRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public NotificationTemplateDataSeedContributor(
INotificationTemplateRepository notificationTemplateRepository,
IUnitOfWorkManager unitOfWorkManager)
{
_notificationTemplateRepository = notificationTemplateRepository;
_unitOfWorkManager = unitOfWorkManager;
}
public async Task SeedAsync(DataSeedContext context)
{
IEnumerable<NotificationTemplate> notificationTemplates = await _notificationTemplateRepository.GetListAsync();
NotificationCode[] notificationCodes = Enum.GetValues<NotificationCode>();
foreach (var notificationCode in notificationCodes)
await InsertIfNotExistAsync(notificationTemplates, notificationCode);
}
private async Task InsertIfNotExistAsync(IEnumerable<NotificationTemplate> notificationTemplates, NotificationCode notificationCode)
{
using IUnitOfWork uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true);
bool isExist = notificationTemplates.Any(x => x.Code == notificationCode);
if (!isExist)
{
NotificationTemplate notificationTemplate = new(notificationCode.ToString(), string.Empty, notificationCode);
await _notificationTemplateRepository.InsertAsync(notificationTemplate);
}
await uow.CompleteAsync();
}
}
13 Answer(s)
-
0
Hello
I think this is same with https://abp.io/support/questions/1271/Add-relation-between-AbpUser-to-My-Table#answer-0ef35452-cfbd-16ad-44c0-39fc57ccd99e
Can you check?
Thank you.
-
0
-
0
Hello
a composite key using
LoginProvider
andProviderKey
, which are meant to be the primary keys forIdentityUserLogin
:protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<IdentityUserLogin>(b => { b.HasKey(l => new { l.LoginProvider, l.ProviderKey }); }); }
Try to this code and check it's work or not ?
Thank you.
-
0
We tried it and the exception remains. What else could be the source of the problem?
-
0
please check once this link https://github.com/abpframework/abp/issues/8019#issuecomment-796776155
-
0
We've tried it and it did not work. I noticed that our solution does not attempt to modify the
TenantConnectionString,
nor do we have the methodbuilder.ConfigureSaas();
So, maybe this is not related to our solution.If you need more investigation, we can share the code with you. How do you feel about sharing the code? And how would you rather us share the code with you?
-
0
Hello ,
Please share your project support@abp.io email along with ticket no.
Thanks,
-
0
Hello ,
Please share your project support@abp.io email along with ticket no.
Thanks,
I already shared the solution with you and mention the ticket number in the share message, below is the link for easy access
https://drive.google.com/file/d/1VA603vKxEUhktFXnMh58phJ0PhoZ_UNN/view?usp=sharing
if you want to see the error only run the migrator project and you will see the error in the seed contributor file of the shared project in module folder
-
0
Any Updates?
-
0
Hi, I got your project now and trying to reproduce the problem. I will write back to you asap.
Regards.
-
0
Hi, I checked your project and found the problem. In your shared.entityframeworkcore project, you should call the
builder.ConfigureIdentityPro()
before your entity configuration. Because you are using theFullAuditedEntityWithUser
in the UserNotification entity.Here is what you should do:
- Add
<PackageReference Include="Volo.Abp.Identity.Pro.EntityFrameworkCore" Version="9.0.4" />
to Shared.EntityFrameworkCore.csproj. - Add
typeof(AbpIdentityProEntityFrameworkCoreModule)
this depends on statement toSharedEntityFrameworkCoreModule
class. - Open the
SharedDbContext
class, and update it as follows (don't forget to addbuilder.ConfigureIdentityPro()
):
using Microsoft.EntityFrameworkCore; using Shared.EntityFrameworkCore.Configurations; using Shared.Notifications; using Shared.NotificationTemplates; using Shared.UserDevices; using Shared.UserNotifications; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Identity; using Volo.Abp.Identity.EntityFrameworkCore; namespace Shared.EntityFrameworkCore; [ReplaceDbContext(typeof(IIdentityProDbContext))] [ConnectionStringName(SharedDbProperties.ConnectionStringName)] public class SharedDbContext : AbpDbContext<SharedDbContext>, ISharedDbContext, IIdentityProDbContext { /* Add DbSet for each Aggregate Root here. Example: * public DbSet<Question> Questions { get; set; } */ public DbSet<UserNotification> UserNotifications { get; set; } public DbSet<Notification> Notifications { get; set; } public DbSet<NotificationTemplate> NotificationTemplates { get; set; } public DbSet<UserDevice> UserDevices { get; set; } public SharedDbContext(DbContextOptions<SharedDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.ConfigureIdentityPro(); builder.ConfigureShared(); } //Identity public DbSet<IdentityUser> Users { get; } public DbSet<IdentityRole> Roles { get; } public DbSet<IdentityClaimType> ClaimTypes { get; } public DbSet<OrganizationUnit> OrganizationUnits { get; } public DbSet<IdentitySecurityLog> SecurityLogs { get; } public DbSet<IdentityLinkUser> LinkUsers { get; } public DbSet<IdentityUserDelegation> UserDelegations { get; } public DbSet<IdentitySession> Sessions { get; } }
Then, run the dbmigrator without having a problem.
- Add
-
0
Thanks, the issue is resolved. So, for each module, if I want to use FullAuditedEntityWithUser or establish a relationship with IdentityUser, I need to follow the same steps, correct?
-
0
Thanks, the issue is resolved. So, for each module, if I want to use FullAuditedEntityWithUser or establish a relationship with IdentityUser, I need to follow the same steps, correct?
Yes, that's right 👍Because, you need to have the relationship for the
IdentityUser
entity.I'm closing the question since your problem is resolved. Best regards.