Introducing FOREIGN KEY constraint "XXX" ..... Could not create constraint or index - c#

I'm setting up a new e-commerce project. I want every category has many sub category and these sub categories has many products in it. My product , category and sub category classes are here;
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public List<SubCategory> SubCategories { get; set; }
}
public class SubCategory
{
public int Id { get; set; }
public string Name { get; set; }
public int ItemsInCategory { get { return Products.Count; } }
public List<Product> Products { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Product
{
public Product()
{
Attributes = new List<Attribute>();
Reviews = new List<Review>();
}
public int ProductId { get; set; }
public string ProductName { get; set; }
public string BrandName { get; set; }
public decimal Price { get; set; }
public bool OnSale { get; set; }
public int SalePercantage { get; set; }
public decimal SalePrice { get; set; }
public string ShortDescription { get; set; }
public string Description { get; set; }
public int SubCategoryId { get; set; }
public SubCategory SubCategory { get; set; }
public List<Attribute> Attributes { get; set; }
public List<Review> Reviews { get; set; }
}
While I'm trying to update database I'm getting this error :
Introducing FOREIGN KEY constraint 'FK_Products_SubCategory_SubCategoryId' on table 'Products' 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.
How can I fix this?

You need to specify in your context the one-to-many relationship , in your case a Product has one SubCategory and a SubCategory has many Product's
modelBuilder.Entity<Product>()
.HasOne(d => d.SubCategory)
.WithMany(p => p.Products)
.HasForeignKey(d => d.SubCategoryId);

Related

EF ... Unwanted duplicate values of two fields

I have two entity for save Product and Product's Related Products ... there is One to Many Relationship ... Everything is right before storing the information But in the database two duplicate fields are stored
RelatedProducID
ProductID
public class RelatedCatalogs : EntityBase
{
public Guid ProductID { get; set; }
public Guid RelatedProducID { get; set; }
public Product RelatedProductCatalog { get; set; }
public int Priority { get; set; }
}
Product Class:
public class Product{
public Guid ProductID { get; set; }
public string Name { get; set; }
[ForeignKey("RelatedProductID")]
public virtual List<RelatedCatalogs> RelatedCatalogs { get; set; }
.
.
.
}
What needs to be done now to fix this problem?
Your problem seems similar to this, so try:
public class Product
{
public Guid ProductID { get; set; }
public string Name { get; set; }
...
[InverseProperty("Product")]
public virtual List<RelatedCatalogs> RelatedCatalogs { get; set; }
}
public class RelatedCatalogs : EntityBase
{
public Guid ID { get; set; }
[ForeignKey("Product")]
public Guid ProductID { get; set; }
public Product Product { get; set; }
[ForeignKey("RelatedProductCatalog")]
public Guid RelatedProductID { get; set; }
public Product RelatedProductCatalog { get; set; }
public int Priority { get; set; }
}
Then you can add the mentioned fluent code to avoid cycles:
modelBuilder.Entity<RelatedCatalogs>()
.HasRequired(r => r.RelatedProductCatalog)
.WithMany()
.HasForeignKey(r => r.RelatedProductID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<RelatedCatalogs>()
.HasRequired(r => r.Product)
.WithMany(p => p.RelatedCatalogs)
.HasForeignKey(r => r.ProductID);

How to define a table that its primary key is constructed from 2 foreign keys with EF code-first

I am using models to define my tables using EF code-first.
I have and Item model and an Order model.
Item:
public class Item
{
public int ItemID { get; set; }
[Required]
public int Price { get; set; }
[Required]
public int AmountLeft { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string FullDescription { get; set; }
[Required]
public DateTime PublishDate { get; set; }
public int CompanyID { get; set; }
public int CategoryID { get; set; }
// Navigation properties
public virtual Company Company { get; set; }
// Navigation properties
public virtual Category Category { get; set; }
}
Order model:
public class Order
{
public int OrderID { get; set; }
[Required]
public DateTime DeliveryDate { get; set; }
[Required]
public string Currency { get; set; }
[Required]
public int TotalAmount { get; set; }
public List<int> Items { get; set; }
public DateTime OrderDate { get; set; }
public int UserID { get; set; }
// Navigation properties
public virtual User user { get; set; }
}
I want to create another table which will be called ItemInOrder which will only have 2 fields: ItemID and OrderID.
the primary key would be these 2 foreign keys.
i tried to define this model:
public class ItemInOrder
{
public int OrderID { get; set; }
public int ItemID { get; set; }
// Navigation properties
public virtual Order order { get; set; }
public virtual Item item { get; set; }
}
But i got errors. i tried to put [Key] notation on both fields but still i got errors.
how will i be able to create the table i want?
When you need to create a table with composite PKs, you need to specify the order of you keys. There are two variants:
You could override the OnModelCreating method on your Context, and try with these Fluent Api configurations:
// Configure the primary keys for the ItemInOrder in the order you want
modelBuilder.Entity<ItemInOrder>()
.HasKey(t => new{t.OrderID,ItemID);
modelBuilder.Entity<ItemInOrder>()
.HasRequired(io=>io.Order)
.WithMany()
.HasForeigKey(io=>io.OrderID);
modelBuilder.Entity<ItemInOrder>()
.HasRequired(io=>io.Item)
.WithMany()
.HasForeigKey(io=>io.ItemID);
The second variant using Data Annotations should be this way:
[Key]
[Column(Order=1)]
[ForeignKey("Order")]
public int OrderID { get; set; }
[Key]
[Column(Order=2)]
[ForeignKey("Item")]
public int ItemID { get; set; }
EF will notice you want to create two relationships and it will do the job for you.

Foreign Key in Code First Entity Framework

My question is this. Let's say I have a Category class and Product class. And they are implemented like this :
Category :
public class Category
{
public Category()
{
this.Products = new ObservableCollection<Product>();
}
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ObservableCollection<Product> Products { get; private set; }
}
And Product :
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
My question is this. If their id names were both "Id", how could I set the same relationship between Category and Product? In this example I can easily put CategoryId in product because the IDs have different names. What if they had the same name? What should I do? Thanks.
I think just renaming their Id(s) to "Id" work perfectly as you expected.
public class Category
{
public Category()
{
this.Products = new ObservableCollection<Product>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ObservableCollection<Product> Products { get; private set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
Result

How do i use navigation properties correctly EF?

Below is a POCO class i set up with Entity Framework Code first. How can i Query my database so that I can return all brands of a specific category?
Example: You have a list of categories and you click on one. It shows all brands of products available under that category.
I don't know if my classes are set up correctly to do this.
public class Product
{
[Key,ScaffoldColumn(false)]
public int ProductID { get; set; }
public string ProductName { get; set; }
public int? CategoryID { get; set; }
public virtual Category Category { get; set; }
public int? BrandID { get; set; }
public virtual Brand Brand { get; set; }
}
public class Brand
{
[ScaffoldColumn(false)]
public int BrandID { get; set; }
public string BrandName { get; set; }
}
public class Category
{
[ScaffoldColumn(false)]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
What about
context.Products.
Where(p => p.Category.CategoryID == categoryToFind).Select(p => p.Brand);
or
var brands = context.Products.
Where(p => p.Category.CategoryID == categoryToFind).
Select(p => p.Brand.BrandName).Distinct().ToList();
if you just need brand names.

EF Code 1st Many to Many with a Primary Key made of 3 fields

I am using EF5 (Code 1st) and doing all my configurations with the Fluent API. My model looks like this:
public class AddressType
{
public int AddressTypeID { get; set; }
public string Name { get; set; }
}
public class Address
{
public int AddressID { get; set; }
public int StateID { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public State State { get; set; }
public ICollection<Person> People { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public ICollection<Address> Addresses { get; set; }
}
My database contains tables for the above classes + the below Many:Many table:
Person.Person2Address
(
PersonID INT NOT NULL,
AddressID INT NOT NULL,
AddressTypeID INT NOT NULL,
)
The 3 fields above are all foreign keys & the 3 together make up the Primary Key for the table.
Typically my M:M setups only involve 2 fields in the PK. And I would map it like this:
var addressCfg = mb.Entity<Address>();
addressCfg.ToTable("Address", "Geo");
addressCfg.HasMany(a => a.People)
.WithMany(p => p.Addresses)
.Map(mmc =>
{
mmc.ToTable("Person2Address", "Person");
mmc.MapLeftKey("AddressID");
mmc.MapRightKey("PersonID");
});
But I don't know how to configure this 3rd field in the PK or how CRUD would even work in EF in this case.
Any examples of how this should be handled would be greatly appreciated.
You can't map this as many-to-many relationship. You need three one-to-many relationships with an intermediate additional entity Person2Address that represents the link table with the three keys. The collections in Person and Address must both refer to this intermediate entity (and optionally also a collection in AddressType).
The model would be like this:
public class AddressType
{
public int AddressTypeID { get; set; }
public string Name { get; set; }
// public ICollection<Person2Address> Person2Addresses { get; set; }
// optionally you can include this collection or not
}
public class Address
{
public int AddressID { get; set; }
public int StateID { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public State State { get; set; }
public ICollection<Person2Address> Person2Addresses { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string Name { get; set; }
public ICollection<Person2Address> Person2Addresses { get; set; }
}
public class Person2Address
{
public int PersonID { get; set; }
public int AddressID { get; set; }
public int AddressTypeID { get; set; }
public Person Person { get; set; }
public Address Address { get; set; }
public AddressType AddressType { get; set; }
}
And the mapping with Fluent API:
modelBuilder.Entity<Person2Address>()
.HasKey(p2a => new { p2a.PersonID, p2a.AddressID, p2a.AddressTypeID });
modelBuilder.Entity<Person2Address>()
.HasRequired(p2a => p2a.Person)
.WithMany(p => p.Person2Addresses)
.HasForeignKey(p2a => p2a.PersonID);
modelBuilder.Entity<Person2Address>()
.HasRequired(p2a => p2a.Address)
.WithMany(a => a.Person2Addresses)
.HasForeignKey(p2a => p2a.AddressID);
modelBuilder.Entity<Person2Address>()
.HasRequired(p2a => p2a.AddressType)
.WithMany()
.HasForeignKey(p2a => p2a.AddressTypeID);
Or use WithMany(at => at.Person2Addresses) in the last mapping if you want to include the collection in AddressType.

Categories