The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Posts_Authors_AuthorId" - asp.net

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

Related

Introducing FOREIGN KEY constraint with ON DELETE NO ACTION doesn't working

I have 4 tables with between them foreign keys as:
Classification - Classification level - Classification value - Classification language
on add-migration it is ok, but when running update-database I get the error:
Introducing FOREIGN KEY constraint 'FK_dbClassificationValue_dbClassificationLevel_ClassificationLevelId' on table 'dbClassificationValue' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.
The tables as mentioned in the error are defined as:
public class SuClassificationLevelModel
{
public int Id { get; set; }
public int ClassificationId { get; set; }
public int Sequence { get; set; }
public bool DateLevel { get; set; }
public bool OnTheFly { get; set; }
public bool Alphabetically { get; set; }
public bool CanLink { get; set; }
public bool InDropDown { get; set; }
public Guid CreatorId { get; set; }
public Guid ModifierId { get; set; }
public DateTime ModifiedDate { get; set; }
public DateTime CreatedDate { get; set; }
public virtual SuClassificationModel Classification { get; set; }
public virtual ICollection<SuClassificationLevelLanguageModel> ClassificationLevelLanguages { get; set; }
public virtual ICollection<SuClassificationValueModel> ClassificationValues { get; set; }
}
and
public class SuClassificationValueModel
{
public int Id { get; set; }
public int ClassificationLevelId { get; set; }
public int ParentValueId { get; set; }
public DateTimeOffset DateFrom { get; set; }
public DateTimeOffset DateTo { get; set; }
public virtual SuClassificationLevelModel ClassificationLevel { get; set; }
public virtual ICollection<SuClassificationValueLanguageModel> ClassificationValueLanguages { get; set; }
}
I have added the delete behavior line in my DBContect class as:
modelBuilder.Entity<SuClassificationValueModel>()
.HasOne(u => u.ClassificationLevel)
.WithMany(u => u.ClassificationValues)
.HasForeignKey(u => u.ClassificationLevelId)
.OnDelete(DeleteBehavior.Restrict);
Also, I have put this on the foreign keys between all tables of the cascading structure.
modelBuilder.Entity<SuClassificationLevelModel>()
.HasOne(u => u.Classification)
.WithMany(u => u.ClassificationLevels)
.HasForeignKey(u => u.ClassificationId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<SuClassificationValueModel>()
.HasOne(u => u.ClassificationLevel)
.WithMany(u => u.ClassificationValues)
.HasForeignKey(u => u.ClassificationLevelId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<SuClassificationValueLanguageModel>()
.HasOne(u => u.ClassificationValue)
.WithMany(u => u.ClassificationValueLanguages)
.HasForeignKey(u => u.ClassificationValueId)
.OnDelete(DeleteBehavior.Restrict);
Further, I have tried to set it for all foreign keys with:
foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
As I don't need the cascading delete behavior.
After these different tries I did again an add-migration and update-database. But the error is still the same.
Any suggestions?
Finally, I went into the migration files and changed everywhere from cascade to restrict. As I don't want to use cascade anyway. And now it works.

Introducing FOREIGN KEY constraint 'FK_Product_User_UserId' on table 'Product' may cause cycles or multiple cascade paths

i cannot create database with ef core
error : Introducing FOREIGN KEY constraint 'FK_Product_User_UserId' on table 'Product' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
this is my product class
{
public Product()
{
}
public Guid UserId { get; set; }
public Guid CategoryId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string PhotoPath { get; set; }
public decimal Price { get; set; }
public Category Category { get; set; }
public User User { get; set; }
}
and
this is my user class
{
public User()
{
Payments = new HashSet<Payment>();
Categories = new HashSet<Category>();
Products = new HashSet<Product>();
}
public string Username { get; set; }
public Guid Password { get; set; }
public ICollection<Payment> Payments { get; set; }
public ICollection<Category> Categories { get; set; }
public ICollection<Product> Products { get; set; }
}
its mapping class
{
public ProductMap()
{
}
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.UserId).IsRequired();
builder.Property(x => x.CreatedDate).IsRequired();
builder.Property(x => x.Description).HasMaxLength(500);
builder.Property(x => x.IsActive).IsRequired();
builder.Property(x => x.Name).HasMaxLength(500).IsRequired();
builder.Property(x => x.PhotoPath).HasMaxLength(4000);
builder.Property(x => x.Price).HasColumnType("decimal(10,3)").IsRequired();
builder.HasOne(x => x.Category).WithMany(x => x.Products).HasForeignKey(x => x.CategoryId);
builder.HasOne(x => x.User).WithMany(x => x.Products).HasForeignKey(x => x.UserId);
}
}
and i cannot create database cause error like this posts title.
what can i do?
Thanks.
You are saying that each user has many Categories and each Category has many Products so you have to remove this line from the User class since it causing cycle path
public ICollection<Product> Products { get; set; }
And also fix the last line of the Configure method:
builder.HasOne(x => x.User).WithMany(x => x.Categories).HasForeignKey(x => x.UserId);

Many-to-Many Relation only includes one Entity [duplicate]

This question already has an answer here:
Many to many relationship mapping in EF Core
(1 answer)
Closed 3 years ago.
Dotnet Core 2.2, EntityFrameworkCore 2.2.3
In a Many-to-Many relation between the entities "Post" and "Category" the linked Entity "PostCategory" returns the "Post" object but for the "Category" object only the Id and not the object itself.
Migrations and database update works fine and all three tables are created.
For the relation itself I tried it with EF "auto magic" and explicit definition of the relation in OnModelCreating in the ApplicationDbContext.
Models
Post-Model
public class Post
{
public int Id { get; set; }
public string Slug { get; set; }
public string Title { get; set; }
public string Abstract { get; set; }
public string Content { get; set; }
public string Author { get; set; }
public DateTime Created { get; set; }
public ICollection<PostCategory> PostCategories { get; set; }
}
Category-Model
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<PostCategory> PostCategories { get; set; }
}
PostCategory Model
public class PostCategory
{
public int PostId { get; set; }
public Post Post { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
DbSets in ApplicationDbContext
public DbSet<Post> BlogPosts { get; set; }
public DbSet<Category> BlogCategories { get; set; }
public DbSet<PostCategory> PostCategories { get; set; }
Get all Posts from Service
public IEnumerable<Post> GetAll()
{
var posts = _context.BlogPosts
.Include(x => x.PostCategories);
return posts;
}
Calling service from Controller
public IActionResult Index()
{
var blogPosts2 = _blogService.GetAll();
...
}
The result is seen in the screenshot.
In ApplicationDbContext I tried two versions:
Version 1:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<PostCategory>()
.HasKey(x => new { x.PostId, x.CategoryId });
}
public DbSet<Post> BlogPosts { get; set; }
public DbSet<Category> BlogCategories { get; set; }
public DbSet<PostCategory> PostCategories { get; set; }
Version 2:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<PostCategory>()
.HasKey(x => new { x.PostId, x.CategoryId });
builder.Entity<PostCategory>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostCategories)
.HasForeignKey(pt => pt.PostId);
builder.Entity<PostCategory>()
.HasOne(pt => pt.Category)
.WithMany(t => t.PostCategories)
.HasForeignKey(pt => pt.CategoryId); ;
}
public DbSet<Post> BlogPosts { get; set; }
public DbSet<Category> BlogCategories { get; set; }
public DbSet<PostCategory> PostCategories { get; set; }
Both version migrate and update with no errors and the same result.
I'm grateful for any help.
Best regards
Edit:
I tried the "ThenInclude" before but obviously my Visual Studio auto completion has a problem:
If I ignore the auto completion, then it works, thank you!
To eager load related data in multiple level, you have to use .ThenInclude as follows:
public IEnumerable<Post> GetAll()
{
var posts = _context.BlogPosts
.Include(x => x.PostCategories)
.ThenInclude(pc => pc.Category);
return posts;
}
Here is the more details: Loading Related Data: Including multiple levels

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 :)

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

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.

Resources