0
votes

I've found a number of other questions like this already but I'm not sure why it's doing it on my entities. In plain English the below representation. Three entities, Account, Site and Contract. An Account can have multiple sites. An Account can have multiple contracts. A site can have multiple contracts. So in some instances you can have a contract attached to a site, which is then attached to an account or a contract attached directly to an account.

I'm assuming I'm getting this because there are two possible cascades for the deletion of a contract, it is either cascaded when an account is deleted and it is directly attached to an account OR it is cascaded when a site is deleted.

I thought as neither AccountId or SiteId are required in Contract, that this should not trigger the error. What I want to be able to do is attached a contract to a site (and subsequently an Account) or attach the contract directly to an account - but I still want to maintain database referential integrity.

Introducing FOREIGN KEY constraint 'FK_dbo.Contract_dbo.Site_SiteId' on table 'Contract' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

My classes/entities:

Account

public partial class Account
{
    public int Id { get; set; }

    [Display(Name = "Account Name")]
    [Required]
    [MinLength(3, ErrorMessage = "The Account Name should be at least 3 characters")]
    [MaxLength(40, ErrorMessage = "The Account Name should be no more than 40 characters")]
    [Remote("IsAccountNameAvailable", "Helper", ErrorMessage = "This Account name already exists, please try another name")]
    public string AccountName { get; set; }

    [ScaffoldColumn(false)]
    [Display(Name = "Date Account Added")]
    public DateTime DateAdded { get; set; }

    public virtual ICollection<Site> Sites { get; set; }
    public virtual ICollection<Contract> Contracts { get; set; }
}

Site

public partial class Site
{
    public int Id { get; set; }

    [Required(ErrorMessage = "A site must be attached to an account - please specify an account")]
    [Display(Name = "Parent Account")]
    public int AccountId { get; set; }

    [Display(Name = "Site Name")]
    [Required]
    [MinLength(3, ErrorMessage = "The Site Name should be at least 3 characters")]
    [MaxLength(40, ErrorMessage = "The Site Name should be no more than 40 characters")]
    public string SiteName { get; set; }

    [ScaffoldColumn(false)]
    public DateTime DateAdded { get; set; }

    [Required]
    [Display(Name = "Primary Site")]

    //[Remote("IsThereAlreadyAPrimarySite", "Helper", AdditionalFields = "AccountId", ErrorMessage = "There is already a primary site set for this account", HttpMethod = "POST")]
    public bool PrimarySite { get; set; }

    [Display(Name = "Site Notes")]
    [Column(TypeName = "text")]
    public string SiteNotes { get; set; }

    public virtual Account Account { get; set; }

    public virtual ICollection<Contract> Contracts { get; set; }

}

Contract

public partial class Contract
{
    public int Id { get; set; }

    public int AccountId { get; set; }
    public int SiteId { get; set; }

    [Display(Name = "Contract Type")]
    [Required]
    public int ContractTypeId { get; set; }

    public virtual Account Account { get; set; }

    public virtual Site Site { get; set; }

    public virtual ContractType ContractType { get; set; }

}
1

1 Answers

0
votes

In your DbContext file override method OnModelCreating where at least one the relations must be configured not to cascade on delete. That relation will have to be explicitly handled on deletion

protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
    base.OnModelCreating( modelBuilder );

    modelBuilder.Entity<Contract>()
        .HasRequired( c => c.Site)
        .WithMany( s => s.Contracts )
        .WillCascadeOnDelete( false );
}