I am trying to develop an ASP.NET MVC 4 application where players can be rated according to their Offence, Defence and Assist skills. Offence, Defence and Assist are foreign keys on Player table referencing the same lookup table - Rating.
I have the following parent entity:
public class Rating
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Player> Players { get; set; }
}
And child entity:
public class Player
{
public int Id { get; set; }
public string Name { get; set; }
public int OffenceRatingId { get; set; }
[ForeignKey("OffenceRatingId")]
public virtual Rating OffenceRating { get; set; }
public int DefenceRatingId { get; set; }
[ForeignKey("DefenceRatingId")]
public virtual Rating DefenceRating { get; set; }
public int AssistRatingId { get; set; }
[ForeignKey("AssistRatingId")]
public virtual Rating AssistRating { get; set; }
}
Building and scaffolding went fine but when I run the app, I get the following error:
Introducing FOREIGN KEY constraint 'FK_dbo.Players_dbo.Ratings_DefenceRatingId' on table 'Players' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I am new to MVC and have no idea what I am missing here. Any help with this will be greatly appreciated. Thanks.
By default, Entity Framework has a Cascade on Delete convention. When two entities have foreign keys to each other, it causes a circular reference and Cascade on Delete can't be applied to both entities.
The simplest solution is to remove the cascade on delete convention, and apply it on a case by case basis.
Related
public class Club
{
public int ClubId { get; set; }
public string Name { get; set; }
public ICollection<Membership> Memberships { get; set; }
}
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public ICollection<Membership> Memberships { get; set; }
}
public class Membership
{
public int ClubId { get; set; }
public int PersonId { get; set; }
public Club Club { get; set; }
public Person Person { get; set; }
}`
...
modelBuilder.Entity<Person>()
.HasMany(p => p.Memberships)
.WithRequired(m => m.Person)
.WillCascadeOnDelete(true);
Above is a simple set up of two independent entities: Club and Person, which may be joined via membership.
I had thought that I could simply retrieve a Person, delete it, and then rely on cascade deleting to remove any Membership records and leave the associated Clubs in place (they exist independently).
Similarly, I had thought that I could simply retrieve a Club, delete it, and then rely on cascade deleting to remove amy Membership records and leave the associated Persons in place (they exist independently).
It seems that when I remove a "Person", EF tries to set the value of Membership.PersonId to null causing a db violation.
Have I misunderstood cascade deleting? And how could I achieve the desired result?
I guess that I could retrieve Person.Include("Membership") and then enumerate each membership and mark as deleted and then finally mark the Person as deleted ... but is this really required or am I missing a trick?
I add provincesModel's pr_id as a foreign Key to clinicsModel. So the visual studio display me this error message
Introducing FOREIGN KEY constraint 'FK_dbo.ClinicsModels_dbo.ProvincesModels_pr_id' on table 'ClinicsModels' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I try to solve the issue by browsing on web to find some solution but I can't get how to solve this. So I remove the foreign key relation of pr_id from clinicsModel and run the project but still visual studio shows me the same error message. I also recreate the ClinicsModel and try to update database using Update-Database -Verebose Migrations using package manager console but still it shows the same error message.
Here's my code:
for ProvinceModel
namespace finalFyp.Models
{
public class ProvincesModel
{
[Key]
public int pr_id { get; set; }
public string pr_name { get; set; }
public ICollection<CitiesModel> cities { get; set; }
}
}
ClinicsModel:
public class ClinicsModel
{
[Key]
public int clinic_id { get; set; }
public string clinic_name { get; set; }
public string clinic_address { get; set; }
//Forigen Keys
public int ct_id { get; set; }
public CitiesModel city { get; set; }
}
}
As the error occurred when I redirecting to http://localhost:3110/Doctors/index
Here's the snapshot of of error message.
DoctorsModel:
public class DoctorsModel
{
[Key]
public int d_id { get; set; }
public string d_name { get; set; }
public string contact { get; set; }
public string cnic { get; set; }
public string email { get; set; }
public string gender { get; set; }
//Forigen Key
public ICollection<DocExperiencesModel> experiences { get; set; }
public ICollection<DocSpecialization> specializations { get; set; }
public ICollection<QualificationsModel> qualifications { get; set; }
public ICollection<DoctorProfileModel> profiles { get; set; }
}
For ease of understanding Here's the schema of my database.
Please guide me what I suppose to do? I will be very thankful to him/her.
From first glance, the error occured when pr_id added as foreign key to ClinicsModel because ProvincesModel has one-to-many relationship against ClinicsModel table which involves pr_id primary key field. Since all foreign keys which referencing pr_id are not nullable, all one-to-many relationships where ProvincesModel involved are having cascade delete enabled by default. Hence, it means when a ClinicsModel entity data is deleted, it will have 2 cascade delete paths: through CitiesModel and directly to ProvincesModel as shown in image below.
As a result, it establishing circular relationship with more than one cascade delete path from ClinicsModel to ProvincesModel which causes error 1785 in SQL Server.
To resolve relationships problem, pr_id foreign keys should declared as Nullable<int>:
public int? pr_id { get; set; }
Likewise, if ct_id (and other int foreign key properties which subjected to possible circular relationships) also returning same error, declare them with same way as above:
public int? ct_id { get; set; }
NB: If Fluent API (and Code First) is being used, try adding these lines below:
// taken from /a/20915232
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
// modified from /a/17127512
// used on all entities with circular relationships
var builder = new DbModelBuilder();
builder.Entity<CitiesModel>()
.HasRequired(x => x.ct_id)
.WithMany()
.WillCascadeOnDelete(false);
builder.Entity<ProvincesModel>()
.HasRequired(x => x.pr_id)
.WithMany()
.WillCascadeOnDelete(false);
Similar issues:
Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why?
Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths
Error message 1785 occurs when you create a FOREIGN KEY constraint that may cause multiple cascade paths
I have a relationship set up between 2 tables using code first and Fluent API. This works and the schema is generated with the correct fields and key assignments. However, my problem is I need to be able to say SupplyPoint.SupplyPointPricing in my resultant Model. What I have below only gives me the other way around.
I figure there must be a way to keep the structure I have but just MAP SupplyPoint.
public partial class SupplyPoint
{
[Key]
public int SupplyPointId { get; set; }
public string SupplyPointName { get; set; }
}
public class SupplyPointPricing
{
public int SupplyPointPricingId { get; set; }
public int? SupplyPointId { get; set; }
[ForeignKey("SupplyPointId")]
public virtual SupplyPoint SupplyPoint { get; set; }
}
Then I use Fluent API and this gives me the 1-1 between the tables and the Schema I expect
modelBuilder.Entity<SupplyPointPricing>()
.HasOptional(a => a.SupplyPoint)
.WithMany()
.HasForeignKey(u => u.SupplyPointId);
Last time I had this problem I had to change the design around and have a foreign key in the SupplyPoint table. On that previous occasion that was OK since it was a 1-1 required where there are always a matching record. This time around I need to keep this structure since there is 1-0 between SupplyPoint and SupplyPointPricing.
This is how I have always done 1-to-1 relationships with my models, without using Fluent mapping:
public partial class SupplyPoint
{
[Key]
public int SupplyPointId { get; set; }
public virtual SupplyPointPricing SupplyPointPricing { get; set; }
}
public class SupplyPointPricing
{
[Key, ForeignKey("SupplyPoint")]
public int SupplyPointId { get; set; }
public virtual SupplyPoint SupplyPoint { get; set; }
}
As you can see, the SupplyPointPricing does not have an Id of its own, but only the Id of the SupplyPoint, which acts as a key in the 1-to-1 relatioship.
The only thing I'm not sure of is if the SupplyPointId can be a nullable int.
This will not create a foreign key on the SupplyPoint, so if you don't have a Pricing, the SupplyPoint.SupplyPointPricing property will be null.
I am working with an existing database, so changing the schema is not an option. Here are the tables aI am working with ...
Product
-------------------------------------
ID - GUID [PK]
Name - varchar(100)
ModelId - GUID [FK1, FK2]
SoftWareVersion - varchar(10) [FK2]
[FK1] Foreign Key to Model table
[FK2] Foreign Composite key to SoftwareVersion table
ProductModel
-------------------------------------
ID - GUID [PK]
ModelName - varchar(100)
SoftwareVersion
-------------------------------------
ID - GUID [PK]
Version - varchar(10)
ModelId - GUID [FK1]
[FK1] Foreign Key to Model table
Each Individual Product has software installed on it. We have several Product Models and each product is, obviously associated with a single model (Product[FK1]).
Over the life of each product model it may have had several software updates/versions. Likewise, the Software may be installed on many Models.
I need to be able to take a ProductID and return the Software Version installed on that specific product. Typically I would get the Software Version associated with the Model of the product I am looking up but the Model may have had several updates. I can't lookup on the Product.SoftwareVersion field alone as that would return ALL the different models on which that software was installed.
So ultimately I need to return the record from SoftwareVersion where the ModelId & Version match that for the product I am looking up.
I would like to return the SoftwareVersion as a property of the Product ...
Product.SoftwareVersion
In my ProductEntity definition I have the following ...
[Table("Product")]
public class ProductEntity
{
[ForeignKey("Model")]
public Guid ModelID { get; set; }
public virtual ProductModelEntity Model { get; set; }
[ForeignKey("SoftwareVersion")]
public String SoftwareVersionNumber { get; set; }
public virtual SoftwareVersionEntity SoftwareVersion { get; set; }
}
So the "ModelID" performs the role of Foreign Key for the Model and as part of a composite foreign key for SoftwareVersion. I cannot however assign multiple ForeignKey attributes to the same property...
[ForeignKey("Model"),ForeignKey("SoftwareVersion")]
public Guid ModelID { get; set; }
public virtual ProductModelEntity Model { get; set; }
I prefer to work with attributes if posible but am open to other techniques as well. (Attributes describe the class directly in the relevent code rather than spreading the definition around the library. It's nice to understand what you are looking at rather than spending time hunting down the defintions ... but I digress!)
Any assistance as always is greatly appreciated.
Thank You
-G
I think the following annotations both will work:
[Table("Product")]
public class ProductEntity
{
public Guid ModelID { get; set; }
public String SoftwareVersionNumber { get; set; }
[ForeignKey("ModelID, SoftwareVersionNumber")]
public virtual ProductModelEntity Model { get; set; }
[ForeignKey("SoftwareVersionNumber")]
public virtual SoftwareVersionEntity SoftwareVersion { get; set; }
}
Or:
[Table("Product")]
public class ProductEntity
{
[ForeignKey("Model"), Column(Order = 1)]
public Guid ModelID { get; set; }
[ForeignKey("Model"), ForeignKey("SoftwareVersion"), Column(Order = 2)]
public String SoftwareVersionNumber { get; set; }
public virtual ProductModelEntity Model { get; set; }
public virtual SoftwareVersionEntity SoftwareVersion { get; set; }
}
I'm struggling with creating a simple one-to-many relationship using Code First in EF. I want it to generate daatabase for me but couldn't figure out how to write these classes so it would create it.
I have these classes:
public class Book
{
public int ID { get; set; }
public string Author { get; set; }
public ICollection<Page> Pages { get; set; }
}
public class Page
{ [Key]
public int BookID { get; set; }
public Book Book { get; set; }
public string OtherField { get; set; }
}
But I get error while it ties to generate database:
Unable to determine the principal end of an association between the types 'MvcApplication1.Models.Page' and 'MvcApplication1.Models.Book'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations
I just want to generate two simple tables, "Book" with ID as primary key, and Page with BookID as a primary and foreign key. It really should be simple but I just can't figure it out.
But that is not one-to-many relationship. That is one-to-one relation ship which says that each book has exactly one page. The error says that it cannot determine if the book or the page is principal in the one-to-one relation.
You must modify your entities like this:
public class Book
{
public int ID { get; set; }
public string Author { get; set; }
public virtual ICollection<Page> Pages { get; set; }
}
public class Page
{
public int ID { get; set; }
public int BookID { get; set; }
public virtual Book Book { get; set; }
public string OtherField { get; set; }
}