EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType - asp.net

I am getting these errors when trying to create a merchant.
FlavorPing.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
FlavorPing.Models.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
UserLogins: EntityType: EntitySet 'UserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
UserRoles: EntityType: EntitySet 'UserRoles' is based on type 'IdentityUserRole' that has no keys defined."
Here is my merchant model:
namespace FlavorPing.Models
{
public class Merchant
{
//Meant to inherit identity.
//[ForeignKey("ApplicationUserId")]
public string ApplicationUserId { get; set; }
[ForeignKey("ApplicationUser")]
public virtual List<ApplicationUser> ApplicationUser { get; set; }
[Key]
public int MerchantID { get; set; }
[Required]
[Display(Name = "Business Name")]
public string MerchantName { get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string email { get; set; }
//need to create formatting here.
[Required]
[Display(Name = "Web Site Link")]
public string website { get; set; }
//public int MenuItemID { get; set; }
public virtual List<MenuItem> MenuItems { get; set; }
public virtual MerchantDetails MerchantDetails { get; set; }
public ICollection<FollowerMenuItemMerchant> FollowerMenuItemMerchants { get; set; }
}
}
Here is the create controller for merchant, which is where I am getting the error:
// POST: Merchants/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "MerchantID,MerchantName,email,website")] Merchant merchant)
{
if (ModelState.IsValid)
{
merchant.ApplicationUserId = User.Identity.GetUserId();
db.Merchants.Add(merchant);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(merchant);
}
Here is my DBContext:
namespace FlavorPing.Models
{
public class FlavorPingContext : IdentityDbContext
{
public FlavorPingContext()
: base("name=FlavorPingContext")
{
}
public System.Data.Entity.DbSet<FlavorPing.Models.Merchant> Merchants { get; set; }
public System.Data.Entity.DbSet<FlavorPing.Models.MenuItem> MenuItems { get; set; }
public System.Data.Entity.DbSet<FlavorPing.Models.MerchantDetails> MerchantDetails { get; set; }
public System.Data.Entity.DbSet<FlavorPing.Models.Follower> Followers { get; set; }
public System.Data.Entity.DbSet<FlavorPing.Models.FollowerMenuItemMerchant> FollowerMenuItemMerchants { get; set; }
public DbSet<IdentityUserLogin> UserLogins { get; set; }
public DbSet<IdentityUserClaim> UserClaims { get; set; }
public DbSet<IdentityUserRole> UserRoles { get; set; }
protected override void OnModelCreating(DbModelBuilder builder)
{
// Primary keys
builder.Entity<Follower>().HasKey(q => q.FollowerID);
builder.Entity<MenuItem>().HasKey(q => q.MenuItemID);
builder.Entity<Merchant>().HasKey(q => q.MerchantID);
builder.Entity<FollowerMenuItemMerchant>().HasKey(q =>
new
{
q.FollowerID,
q.MenuItemID,
q.MerchantID
});
// Relationships
builder.Entity<FollowerMenuItemMerchant>()
.HasRequired(t => t.Follower)
.WithMany(t => t.FollowerMenuItemMerchants)
.HasForeignKey(t => t.FollowerID);
builder.Entity<FollowerMenuItemMerchant>()
.HasRequired(t => t.MenuItem)
.WithMany(t => t.FollowerMenuItemMerchants)
.HasForeignKey(t => t.MenuItemID);
builder.Entity<FollowerMenuItemMerchant>()
.HasRequired(t => t.Merchant)
.WithMany(t => t.FollowerMenuItemMerchants)
.HasForeignKey(t => t.MerchantID);
builder.Conventions.Remove<PluralizingTableNameConvention>();
builder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
}
}
I am trying to follow the example (option2) in this link: EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType
I am trying Option 2 because I want to avoid having two DB's. But I am new to managing a DB so if you think I should do Option 3 please advise as to why, or if you see why I am getting this error please tell me why. Thanks in advance!

Ok I fixed my issue by adding this into my DBContext class.
builder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
builder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
builder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });

I think you get the errors because your foreign key attributes aren't in the correct spot (and have the wrong name), instead of this:
public string ApplicationUserId { get; set; }
[ForeignKey("ApplicationUser")]
public virtual List<ApplicationUser> ApplicationUser { get; set; }
You need to do this:
[ForeignKey("ApplicationUser")]
public string ApplicationUserId { get; set; }
public virtual List<ApplicationUser> ApplicationUser { get; set; }
The ID is the foreign key to the virtual entity, not the other way around.

Related

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Posts_Authors_AuthorId"

I successfully built migrations, and I am now trying to update the database with my models in Asp.net core but it keeps giving me this error
"The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Posts_Authors_AuthorId". The conflict occurred in database "MediumDb", table "dbo.Authors", column 'AuthorId'.
The statement has been terminated."
This is what the code in my Post class looks like
namespace Medium.Api.Entities
{
public class Post
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int NoOfClaps { get; set; }
public DateTime CreatedDate { get; set; }
public IQueryable<Tag> Tags { get; set; }
public IQueryable<PostTag> PostTags { get; set; }
public string Image { get; set; }
// public string Video { get; set; }
public Author Author { get; set; }
public int AuthorId { get; set; }
while the code in my Author class says this
namespace Medium.Api.Entities
{
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
public IQueryable<Post> Posts { get; set; }
}
}
This is my DbContext configuration
{
public class MediumApiContext : DbContext
{
public MediumApiContext(DbContextOptions options)
: base(options)
{
// Database.EnsureCreated();
}
public DbSet<Post> Posts { get; set; }
public DbSet<Author> Authors { get; set; }
public DbSet<Tag> Tags { get; set; }
public DbSet<PostTag> PostTags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Author>()
.HasKey(a => a.AuthorId);
modelBuilder.Entity<Author>()
.HasMany(a => a.Posts)
.WithOne(p => p.Author);
modelBuilder.Entity<Post>()
.ToTable("Posts");
modelBuilder.Entity<Post>()
.HasKey(p => p.Id);
modelBuilder.Entity<Post>()
.HasOne(p => p.Author)
.WithMany(a => a.Posts);
modelBuilder.Entity<Post>()
.Property(p => p.CreatedDate)
.IsRequired()
.HasColumnType("Date")
.HasDefaultValueSql("getutcdate()");
modelBuilder.Entity<Post>()
.Property(p => p.Title)
.IsRequired();
modelBuilder.Entity<Post>()
.Property(p => p.NoOfClaps)
.IsRequired();
modelBuilder.Entity<Post>()
.Property(p => p.Content)
.IsRequired();
I don't know where I seem to be getting it all wrong. Please
We Use FK for data integrity right now you have FOREIGN KEY with Author Table so :
"The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Posts_Authors_AuthorId". The conflict occurred in database "MediumDb", table "dbo.Authors", column 'AuthorId'. The statement has been terminated."
This means that when you create a Post, you must give an Author_ID that is on the Author table

EF Core 3.1.4 Navigation property returning null in One-To-One relationship

I am having a problem where a navigation property is always returning null in a One-to-One relationship in EF Core 3.1.4.
My models are structured like so:
public class UserCredential
{
public Guid Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public byte[] Salt { get; set; }
public bool IsLocked { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
public DateTime? DeletedDate { get; set; }
public UserProfile UserProfile { get; set; }
}
public class UserProfile
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Suffix { get; set; }
public bool IsDeleted { get; set; }
public List<Address> Addresses {get;set;}
public DateTime DOB { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
public DateTime? DeletedDate { get; set; }
public Guid UserCredentialId { get; set; }
public UserCredential UserCredential { get; set; }
}
Based off what I understand, that should have been enough for EF Core to infer the One-To-One relationship. But it didnt work so I defined the relationshup in my dbContext like so:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<UserProfile>(entity =>
{
entity.HasOne(up => up.UserCredential)
.WithOne(uc => uc.UserProfile)
.HasForeignKey<UserProfile>( up => up.UserCredentialId);
});
}
I checked the db and there is a foreign key from UserProfile -> UserCredentials defined in the table. Likewise both tables have Id as a primary key.
If I post data to a "addUser" endpoint it will be added correctly in the db.
{
"username": "test3",
"password": "password123",
"UserProfile":{
"FirstName": "John",
"LastName": "Doe"
}
}
Db Screenshot
However "UserProfile" in my model is always null.
System.NullReferenceException: 'Object reference not set to an
instance of an object.'
IronCarp.Identity.Models.UserCredential.UserProfile.get returned null.
I'm using a repository to interact with the db and the method that is returning my data/model seems simple enough.
private async Task<UserCredential> GetUserCredentials(string username)
{
return await context.UserCredentials.Where(u => u.Username == username).FirstOrDefaultAsync();
}
Any help is appreciated, I am not sure what I am missing, thanks!
try to include navigation property in linkq, try something like this:
private async Task<UserCredential> GetUserCredentials(string username)
{
return await context.UserCredentials.Include(x => x.UserProfile).Where(u => u.Username == username).FirstOrDefaultAsync();
}
For me this issue was happening intermittently in my integration tests.
It turned out because I was mistakenly registering the EF Core DbContext as Transient and not Scoped:
Services.AddDbContext<SubscriptionsContext>(
options => options.UseNpgsql(appConfig.DatabaseConnectionString,
optionsBuilder => optionsBuilder.EnableRetryOnFailure(3)), ServiceLifetime.Transient);
Should be:
Services.AddDbContext<SubscriptionsContext>(
options => options.UseNpgsql(appConfig.DatabaseConnectionString,
optionsBuilder => optionsBuilder.EnableRetryOnFailure(3)), ServiceLifetime.Scoped);
If you look at the default parameter on the AddDbContext() extension method, it's always Scoped:

How to define two FK in the same table?

I have a table called User which inherit the properties from IdentityUser, inside that table I added a reference to the UserFriendship table which need to store all the user friendship:
public class User : IdentityUser
{
public string FirstName { get; set; }
public DateTime BirthDate { get; set; }
public virtual ICollection<UserFriendship> UserFriendship { get; set; }
}
Essentially the UserFriendship contains two users, who are those who have a common friendship, this is the model definition:
public class UserFriendship
{
public int Id { get; set; }
[Key, ForeignKey("UserA")]
public string UserAId { get; set; }
public User UserA { get; set; }
[Key, ForeignKey("UserB")]
public string UserBId { get; set; }
public User UserB { get; set; }
[Required]
public DateTime DateTime { get; set; }
}
I defined the UserA and the UserB which are two FK of a User that are contained inside AspNetUsers table.
Now inside the FluentAPI I declared the following:
builder.Entity<UserFriendship>(entity =>
{
entity.HasKey(f => f.Id);
entity.HasOne(u => u.UserA)
.WithMany(n => n.UserFriendships)
.HasForeignKey(u => u.UserAId)
.IsRequired();
entity.HasOne(u => u.UserB)
.WithMany(n => n.UserFriendships)
.HasForeignKey(u => u.UserBId)
.IsRequired();
});
when I execute this command:
add-migration InitialMigration -context MyAppContext
I'll get:
Cannot create a relationship between 'User.UserFriendships' and 'UserFriendship.UserB', because there already is a relationship between 'User.UserFriendships' and 'UserFriendship.UserA'. Navigation properties can only participate in a single relationship.
I'm not an expert of EnityFramework, but based on that error I think that I cannot define two FK in the same table?
Sorry for any mistake, thanks.
You can define more than one FK in table.
The problem here is you are pointing two times to one navigation property - UserFriendships. The solution would be to create two navigation properties.
Navigation properties are used to browse the related data for specified foreign-key (you have one-to-many relationship) of entity.
Try this:
public class User
{
public string FirstName { get; set; }
public DateTime BirthDate { get; set; }
public ICollection<UserFriendship> UserAFriendships { get; set; }
public ICollection<UserFriendship> UserBFriendships { get; set; }
}
public class UserFriendship
{
public int Id { get; set; }
public string UserAId { get; set; }
public User UserA { get; set; }
public string UserBId { get; set; }
public User UserB { get; set; }
public DateTime DateTime { get; set; }
}
And define the relationship through fluent api as following:
modelBuilder.Entity<UserFriendship>(entity =>
{
entity.HasKey(f => f.Id);
entity.HasOne(u => u.UserA)
.WithMany(n => n.UserAFriendships)
.HasForeignKey(u => u.UserAId)
.IsRequired();
entity.HasOne(u => u.UserB)
.WithMany(n => n.UserBFriendships)
.HasForeignKey(u => u.UserBId)
.IsRequired();
});
What is more - you don't need to specify attributes Key, ForeignKey if you use Fluent API.

How to extend Application User to hold a collection of orders?

I'm trying to extend Application User (using Code-First) to hold a collection of orders, but I'm getting errors.
My Order class is
public class Order
{
public Order()
{
OrderDetails = new HashSet<OrderDetails>();
}
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public string UserId { get; set; }
public bool IsDelivered { get; set; }
public bool IsReturned { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual ICollection<OrderDetails> OrderDetails { get; set; }
}
And I'm trying to extend Application user like this
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string CompanyName { get; set; }
public string Profession { get; set; }
public string TaxAuthority { get; set; }
public string TaxNumber { get; set; }
public string Address { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Region { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
public string MobilePhone { get; set; }
public bool NewsLetterSubscribe { get; set; } = false;
public DateTime TimeStamp { get; set; } = DateTime.Now;
public ICollection<Order> Orders { get; set; }
}
And I'm getting the following errors:
QCMS.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
QCMS.Models.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
Can you please help me to solve this problem?
UPDATE:
I'm using two db contexts. The one provided for Individual User Account (when the project is first created) and a second one named "qvModel" that is for all other database classes of my project.
public partial class qvModel : DbContext
{
public qvModel()
: base("name=qvModel")
{
}
//APPSETTINGS
public virtual DbSet<AdminLog> AdminLog { get; set; }
public virtual DbSet<WebLog> WebLog { get; set; }
//LANGUAGES
public virtual DbSet<Language> Languages { get; set; }
.
.
.
public virtual DbSet<Order> Orders { get; set; }
public virtual DbSet<OrderDetails> OrderDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Precision attribute for decimals
Precision.ConfigureModelBuilder(modelBuilder);
modelBuilder.Entity<Language>()
.HasMany(e => e.Brochures)
.WithRequired(e => e.Language)
.WillCascadeOnDelete(true);
.
.
.
modelBuilder.Entity<Order>()
.HasMany(c => c.OrderDetails)
.WithRequired(c => c.Order)
.WillCascadeOnDelete(true);
modelBuilder.Entity<ApplicationUser>()
.HasMany(c => c.Orders)
.WithRequired(c => c.User)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
}
I found a solution that is very simple.
The solution is to inherit from IdentityDbContext like this
public class qvModel : IdentityDbContext<ApplicationUser>
{
public qvModel()
: base("name=qvModel")
{
}
I was also missing the following line from OnModelCreating
base.OnModelCreating(modelBuilder);
After these changes, my migration is working and I stopped getting the errors I mentioned.

Many to many relation between Identity and custom table. EF7 - Code first

How can I make many to many relation between AspNetRoles from Identity 3.0 and my custom table? I want simple 3 table, with both PermissionId and RoleId, something like AspNetUsersRole. I have something like this:
public class Permission
{
public int PermissionId { get; set; }
public string Name { get; set; }
public virtual ICollection<ApplicationRole> Roles { get; set; }
}
public class ApplicationRole : IdentityRole
{
public virtual ICollection<Permission> Permissions { get; set; }
}
But when I want to add migration, I got error:
Unable to determine the relationship represented by navigation property 'ApplicationRole.Permissions' of type 'ICollection<Permission>'. Either manually configure the relationship, or ignore this property from the model.
EF Core (EF7) does not currently support many to many relationship without a join entity. (Reference)
So, what you should do is to create an entity class for the join table and mapping two separate one-to-many relationships. Like;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.HasKey(t => new { t.PostId, t.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Regarding to this question answer, it can be done more easily like this-
class Photo
{
public int Id { get; set; }
public ICollection<PersonPhoto> PersonPhotos{ get; set; }
}
class PersonPhoto
{
public int PhotoId { get; set; }
public Photo Photo { get; set; }
public int PersonId { get; set; }
public Person Person { get; set; }
}
class Person
{
public int Id { get; set; }
public ICollection<PersonPhoto> PersonPhotos{ get; set; }
}
Be sure to configure PersonPhoto with a composite key:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PersonPhoto>().HasKey(x => new { x.PhotoId, x.PersonId });
}
To navigate, use a Select:
// person.Photos
var photos = person.PersonPhotos.Select(c => c.Photo);
Add This namespace-
using Microsoft.AspNetCore.Identity;
public class Permission
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PermissionId { get; set; }
public string Name { get; set; }
public string UserIdFK { get; set; } //Foreign Key of Identity tbl
[ForeignKey("UserIdFK")]
public IdentityUser UserDetail { get; set; }
}
That's it, Happy coding :)

Resources