EF CodeFirst - cannot create database - entity-framework

I am getting error while trying to run my MVC application
Introducing FOREIGN KEY constraint 'FK_dbo.Passages_dbo.Localizations_ToID' on table 'Passages' 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'
I`ve seen many posts but I couldn't get what should I do now.
There are my models:
public class Passage
{
[Key]
public int ID { get; set; }
public int FromID { get; set; }
[ForeignKey("FromID")]
public Localization FromLocalizaton { get; set; }
public int ToID { get; set; }
[ForeignKey("ToID")]
public Localization ToLocalization { get; set; }
public DateTime DepartureTime { get; set; }
public DateTime ArrivalTime { get; set; }
public DateTime? AdditionalTime { get; set; }
public bool Weekend { get; set; }
public int Seats { get; set; }
}
public class Localization
{
[Key]
public int ID { get; set; }
public string Province { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string StreetAdres { get; set; }
}
Passage has two foreign key refers to Lozalization with one to one relationship

The issue came from this:
Passage has two foreign key refers to Lozalization with one to one relationship
Because by default those two relationships are required in Passage (look at foreign key FromID and ToID there are not Nullable<int> or int?) hence Code First create cascade delete action on those relations. However two cascade deletions will be applied on the same table which is not allowed.
To correct this issue, you have two solutions:
Make one of the foreign key property Nullable<int> which by default not create a cascade delete action on that relationship.
Or you can disable cascade delete action by using Fluent API like this :
// Assuming that you want to disable cascade deletion with ToLocalization
modelBuilder.Entity<Passage>()
.HasRequired(p => p.ToLocalization)
.WithMany()
.WillCascadeOnDelete(false);

Related

EF Many to Many cascading delete

I have an issue.
I have some classes that look like this:
public class Question
{
public int Id { get; set; }
[Required] [MaxLength(255)] public string Text { get; set; }
public int CriteriaId { get; set; }
public int QuestionGroupId { get; set; }
public QuestionGroup QuestionGroup { get; set; }
public virtual IList<Answer> Answers { get; set; }
public virtual Criteria Criteria { get; set; }
}
public class Answer
{
public int Id { get; set; }
[Required] [MaxLength(255)] public string Text { get; set; }
public int QuestionId { get; set; }
public Question Question { get; set; }
public virtual IList<State> States { get; set; }
}
public class Criteria
{
public int Id { get; set; }
[Required] [MaxLength(100)] public string Name { get; set; }
public virtual IList<State> States { get; set; }
public IList<Question> Questions { get; set; }
}
public class State
{
public int Id { get; set; }
public int CriteriaId { get; set; }
[Required] [MaxLength(100)] public string Name { get; set; }
public int Score { get; set; }
public virtual IList<Filter> Filters { get; set; }
public Criteria Criteria { get; set; }
}
They have a many to many relationship, so I created this mapping:
modelBuilder.Entity<Answer>()
.HasMany(m => m.States)
.WithMany()
.Map(m => {
m.MapLeftKey("AnswerId");
m.MapRightKey("StateId");
m.ToTable("AnswerStates");
});
When I tried to update my database I get an error about foreign keys.
So I added this line (as a temporary fix):
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
But I need the cascading delete.
I can't seem to figure out why it won't let me have it.
The error I get when trying to include cascading deletes is:
Introducing FOREIGN KEY constraint 'FK_dbo.AnswerStates_dbo.States_StateId' on table 'AnswerStates' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I hope I have provided enough information. Does anyone know what I can do to allow the cascading delete (I need to be able to delete a State or an Answer and it to remove the record from AnswerStates
This is pretty much the same as another question (Deleting only one entry from Many-to-Many relationship) I was answering today. Just your case is a bit more complicated.
The multiple cascade path in your case is from Criteria to AnswerStates. When deleting a Criteria record, the AnswerStates records can be deleted either by Criteria->States->AnswerStates or Criteria->Questions->Answers->AnswerStates relationships.
The solution is always one and the same - turn one of the relationships cascade delete off and handle deletion either manually or via trigger.
In this particular case, my suggestion is to turn Criteria->States cascade delete off:
modelBuilder.Entity<Criteria>()
.HasMany(m => m.States)
.WithRequired(d => d.Criteria)
.HasForeignKey(d => d.CriteriaId)
.WillCascadeOnDelete(false);
and use something like this before deleting a Criteria:
db.States.RemoveRange(db.States.Where(s => s.CriteriaId == criteriaId_to_be_removed));

Entity framework code first cant create primary and foreign key relationship

I am trying to create a relationship between two tables but keep getting the following error:
The ForeignKeyAttribute on property 'CallLogId' on type
'Ylp.Web.ParkingApi.DataLayer.Entities.ApiCallLogDetailEntity' is not
valid. The navigation property 'ApiCallLog' was not found on the
dependent type
'Ylp.Web.ParkingApi.DataLayer.Entities.ApiCallLogDetailEntity'. The
Name value should be a valid navigation property name.
DbContextMapping:
modelBuilder.Entity<ApiCallLogDetailEntity>()
.HasRequired<ApiCallLogEntity>(p => p.ApiCallLog);
Primary table:
[Table("ApiCallLog")]
public class ApiCallLogEntity
{
[Key, Column(Order = 0)]
public string CallLogId { get; set; }
[Key, Column(Order = 1)]
public string UserId { get; set; }
[Required]
public string CallFilterId { get; set; }
[Required]
public DateTime LastUpdated { get; set; }
[Required]
public int Count { get; set; }
public virtual ICollection<ApiCallLogDetailEntity> Details { get; set; }
}
foreign table:
[Table("ApiCallLogDetail")]
public class ApiCallLogDetailEntity
{
[ForeignKey("ApiCallLog")]
public string CallLogId { get; set; }
[Required]
public string PrametersHashCode { get; set; }
[Required]
public DateTime LastUpdated { get; set; }
public ApiCallLogEntity ApiCallLog { get;}
}
The foreign key must refer to the whole primary key of the parent table. In your parent table you have a composite primary key which includes CallLogId and UserId. The message is confusing, but this can be part of the error. Is it really necessary to include the UserId in the PK?
Another error is that you have not defined the PK in the dependent table. If the UserId is also necessary on the PK, include it in the dependent table, and make it part of the FK.

EF Code First Error

I am trying to create some tables using Code First. Here is my code:
public class Country
{
[Key]
public int Id { get; set; }
public string CountryName { get; set; }
}
public class State
{
[Key]
public int Id { get; set; }
public string StateName { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
}
public class Customer
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
public int StateId { get; set; }
public virtual Country Country { get; set; }
public virtual State State { get; set; }
}
public class ProductContext : DbContext
{
public DbSet<Country> Country { get; set; }
public DbSet<Customer> Customer { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
When I Execute this code the following error occurs:
Introducing FOREIGN KEY constraint
'FK_dbo.State_dbo.Country_CountryId' on table 'State' 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. See previous errors.
But I want the CountryId in State Table to be a foreign key. What am I missing here? Can anybody guide me the correct way of achieving this?
Entity Framework is worried about deletion here- because the User has a direct relationship to a Country and also a State and the State also relates to a Country you effectively have a potential loop of User -> State -> Country -> User which would mean that if cascade deletions were enabled the moment you deleted one user you would potentially delete everything in your database.
The answer is in the error message- by disabling cascade deletions across some of these relationships ( which is logical - deleting a user doesn't mean you want to delete their state and country ) you will avoid this risk. As you might imagine this has come up on SO before.
As an aside, having the Country on the User and also on the State looks like questionable denormalisation - there may be a good reason for it, but that happens less often than you would expect.

Why is cascade delete not on by default for this relationship?

I have a 1 to many relationship between LabelLineItem and DespatchPart.
I can't understand why cascade delete is off for this relationship.
There is no relationship defined in the context using the fluent API.
There is no LabelLineItems navigation collection in DespatchPart, so there is no reference back to LabelLineItem.
public class LabelLineItem
{
public int Id { get; set; }
public int DespatchPartId { get; set; }
public int LabelConfigId { get; set; }
public string Content { get; set; }
// Navigation
public virtual LabelConfig LabelConfig { get; set; }
public virtual DespatchPart DespatchPart { get; set; }
}
public class DespatchPart
{
public int Id { get; set; }
public int DespatchId { get; set; }
// Navigation
public virtual Despatch Despatch { get; set; }
//...
}
It's my understanding that one-to-many relationships default to cascade delete on. As demonstrated in the code sample above.
Whereas zero-or-one-to-many relationships default to cascade delete off as would be the case if either:
- DespatchPartId was declared as int?,
- The fluent API declared the relationship as optional i.e. DespatchPart.HasMany(p => p.LabelLineItems).WithOptional(i => i.DespatchPart).
But neither of these are the case which is why I'm confused.
FYI -
I'm certain the cascade is off, because when I tested the cascade delete by removing a despatch part record (in SQLManagementStudio), I received an attempted FK violation in the LableLineItem table as I tried to remove a referenced DespatchPart record. This wouldn't have occurred if it the delete had cascaded to the LabelLineItem table.

code first one-to-one enable cascade delete

I have one to one relationship with foreign keys but the Cascade Delete is not enabled for some reason. The sample code is below.
public class AppRegistration
{
public int AppRegistrationId { get; set; }
[Required]
[StringLength(50)]
[Display(Name = "Username")]
public string UserName { get; set; }
[Required]
[StringLength(100)]
public string Password { get; set; }
[StringLength(20)]
public string StudentOrAgent { get; set; }
// navigation properties
public virtual AppStatus AppStatus { get; set; }
public virtual Agreement Agreement { get; set; }
public virtual AnotherTable AnotherTable { get; set; }
}
The dependent table with a foreign key is below.
public class Agreement
{
[Key]
[ForeignKey("AppRegistration")]
public int AppRegistrationId { get; set; }
public DateTime DateAgreed { get; set; }
public virtual AppRegistration AppRegistration { get; set; }
}
When I try to delete an entry from the generated AppRegistrations table I get a Reference constraint conflict.
I tried putting [Required] on the navigation property in the dependent table but it doesn't do anything - the Update-Database command shows the No pending code-based migrations. message. Any ideas? Thanks.
Update:
I'm getting the following error message:
The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.AppStatus_dbo.AppRegistrations_AppRegistrationId". The conflict occurred in database "MVCapp", table "dbo.AppStatus", column 'AppRegistrationId'.
I decided to work out the cascade delete problem in a separate sample project. I found the following blog & MSDN pages very useful.
http://blog.bennymichielsen.be/2011/06/02/entity-framework-4-1-one-to-one-mapping/
http://msdn.microsoft.com/en-us/library/gg671256%28v=VS.103%29.aspx
http://msdn.microsoft.com/en-us/library/gg671273%28v=VS.103%29.aspx
Using the Code First approach create the following Model.
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public virtual Book Book { get; set; }
}
public class Book
{
public int CategoryId { get; set; }
public string BookTitle { get; set; }
public string BookAuthor { get; set; }
public string BookISBN { get; set; }
public virtual Category Category { get; set; }
}
(I realize the entity names suggest one-to-many relationship, but I am trying to model 1-to-1 relationship, as in my original question at the top.)
So, in the above model each Category can only have one Book.
In your DbContext-derived class add the following.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Book>()
.HasKey(t => t.CategoryId);
modelBuilder.Entity<Category>()
.HasRequired(t => t.Book)
.WithRequiredPrincipal(t => t.Category)
.WillCascadeOnDelete(true);
}
(The following namespaces are required for the above code: System.Data.Entity, System.Data.Entity.ModelConfiguration.Conventions.)
This properly creates the 1-to-1 relationship. You'll have a primary key in each table and also a foreign key in Book table with ON DELETE CASCADE enabled.
In the above code, on the Category entity I used WithRequiredPrincipal() with t => t.Category argument, where the argument is the foreign key column in the dependent table.
If you use WithRequiredPrincipal() without an argument you'll get an extra column in the Book table and you'll have two foreign keys in the Book table pointing to CategoryId in Category table.
I hope this info helps.
UPDATE
Later on I found answer directly here:
http://msdn.microsoft.com/en-us/data/jj591620#RequiredToRequired
A reason why you're not getting cascading delete is because your relationship is optional.
If you want the relationship required i.e. an AppRegistration has to have one Agreement you can use (cascading delete configured automatically):
public class Agreement
{
...
[Required]
public AppRegistration AppRegistration{ get; set; }
}
If you want the relationship to be optional with cascading delete you can configure this using Fluent API:
modelBuilder.Entity<AppRegistration>()
.HasOptional(a => a.Agreement)
.WithOptionalDependent()
.WillCascadeOnDelete(true);