TykiMikk
TykiMikk

Reputation: 1068

Introducing FOREIGN KEY constraint 'FK_dbo.Tickets_dbo.AspNetUsers_UserID' on table 'Tickets' may cause cycles or multiple cascade paths

The Administrator column that you can see from my cshtml page is IssuedTo. Issue to is linked to id in my AspNetUsers.

I'm trying to display the name of what the IssueTo is pointing at so if it's 1 it displays Andy Domagas instead of 1.

enter image description here enter image description here

I tried to create a virtual ApplicationUser property for IssuedTo like I did with UserID public int UserID { get; set; } and [ForeignKey("UserID")] public virtual ApplicationUser User { get; set; } (which allows me to associate User with the property UserID). But when I tried to do it with IssueTo

In my Ticket class

[ForeignKey("IssuedTo")] public virtual ApplicationUser adminAssigned { get; set; }

and in my Ticket\Index.cshtml

    <th>
        @Html.DisplayNameFor(model => model.adminAssigned)
    </th>

    <td>
        @Html.DisplayFor(modelItem => item.adminAssigned)
    </td>

I get an error saying

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code

Additional information: Unable to complete operation. The supplied SqlConnection does not specify an initial catalog or AttachDBFileName.

pointing to

public class TicketController : Controller
{
    private ApplicationDbContext db = new ApplicationDbContext();

    // GET: Ticket
    public ActionResult Index()
    {
        var tickets = db.Tickets.Include(t => t.Category).Include(t => t.User); <---ERROR ON THIS LINE
        return View(tickets.ToList());
    }

Which is weird because my database was working before. So I then specified the databasename by:

<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=RecServDatabase;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" providerName="System.Data.SqlClient" />

and then I get

Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.

So I deleted my database and updated it again using update-database

Introducing FOREIGN KEY constraint 'FK_dbo.Tickets_dbo.AspNetUsers_UserID' on table 'Tickets' 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.

Is it because my ticket table doesn't have AspnetUsers_ID so I need to create a column in it in my Confiuguration.cs file(Seed method)??

Configuration.cs(Ticket Snippet)

    var tickets = new List<Ticket>
    {
        new Ticket {
            UserID = users.Single(s => s.LastName == "West").Id, //UserID
            CategoryID = categories.Single(c => c.CategoryName == "Con-X" ).CategoryID,
            Issue = ("Con-X Login Error"),
            Priority = Priority.High
        },
        new Ticket {
            UserID = users.Single(s => s.LastName == "West").Id, //UserID
            CategoryID = categories.Single(c => c.CategoryName == "Desktop" ).CategoryID,
            Issue = ("Can't remote access C0123"),
            Priority = Priority.Med
        },
    };


    foreach (Ticket e in tickets)
    {
        var ticketInDataBase = context.Tickets.Where(
            s =>
                s.User.Id == e.UserID && //UserID
                s.Category.CategoryID == e.CategoryID).SingleOrDefault();
        if (ticketInDataBase == null)
        {
            context.Tickets.Add(e);
        }
    }
    context.SaveChanges();
}

Ticket.cs

public class Ticket
{
    public int? TicketID { get; set; }
    public int UserID { get; set; }
    [ForeignKey("UserID")]
    public virtual ApplicationUser User { get; set; }

    [ForeignKey("IssuedTo")]
    public virtual ApplicationUser adminAssigned { get; set; }

}

Update After Suggestion

Ticket.cs (Added adminAssigned)

    public int UserID { get; set; }
    //Added Required
    [Required]
    [ForeignKey("UserID")]
    public virtual ApplicationUser User { get; set; }
    //Added IssueID after update
    public int IssueID{ get; set; }
    //Added Required
    [Required]
    [ForeignKey("IssuedID")]
    public virtual ApplicationUser IssuedUser { get; set; }

IdentityModel.cs(ApplicationUser) (Added TicketsIssuedTo)

public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
{
    public async Task<ClaimsIdentity>
        GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
    {
        var userIdentity = await manager
            .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }

    public virtual ICollection<Ticket> Tickets { get; set; }

    public virtual ICollection<ApplicationUser> TicketsIssuedTo { get; set; }    
}

ApplicationDBContext inside IdentityModel.cs (Added OnModelCreating Method)

public class ApplicationDbContext
    : IdentityDbContext<ApplicationUser, ApplicationRole, int,
    ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }


    public DbSet<Ticket> Tickets { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Department> Departments { get; set; }
    public DbSet<Depot> Depots { get; set; }

}

IdentityModel.cs

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace RecreationalServicesTicketingSystem.Models
{
    public class ApplicationUserLogin : IdentityUserLogin<int> { }
    public class ApplicationUserClaim : IdentityUserClaim<int> { }
    public class ApplicationUserRole : IdentityUserRole<int> { }

    public class ApplicationRole : IdentityRole<int, ApplicationUserRole>, IRole<int>
    {
        public string Description { get; set; }

        public ApplicationRole() : base() { }
        public ApplicationRole(string name)
            : this()
        {
            this.Name = name;
        }

        public ApplicationRole(string name, string description)
            : this(name)
        {
            this.Description = description;
        }
    }

    public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
    {
        public async Task<ClaimsIdentity>
            GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
        {
            var userIdentity = await manager
                .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            return userIdentity;
        }

        public bool IsAdministrator { get; set; }
        [StringLength(50, MinimumLength = 1)]

        public string LastName { get; set; }
        [StringLength(50, MinimumLength = 1, ErrorMessage = "First name cannot be longer than 50 characters.")]

        [Column("FirstName")]
        public string FirstMidName { get; set; }

        public string FullName
        {
            get { return FirstMidName + " " + LastName; }
        }
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EnrollmentDate { get; set; }
        public int DepartmentID { get; set; }
        [ForeignKey("DepartmentID")]
        public virtual Department Department { get; set; }
        public int DepotID { get; set; }
        [ForeignKey("DepotID")]
        public virtual Depot Depot { get; set; }
        public virtual ICollection<Ticket> Tickets { get; set; }
        public virtual ICollection<ApplicationUser> IssuedTo { get; set; }
    }


    public class ApplicationDbContext
        : IdentityDbContext<ApplicationUser, ApplicationRole, int,
        ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        }
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }

        static ApplicationDbContext()
        {
            Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
        }


        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }


        public DbSet<Ticket> Tickets { get; set; }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Department> Departments { get; set; }
        public DbSet<Depot> Depots { get; set; }

  //      public System.Data.Entity.DbSet<RecreationalServicesTicketingSystem.Models.ApplicationUser> ApplicationUsers { get; set; }
    }



    public class ApplicationUserStore :
    UserStore<ApplicationUser, ApplicationRole, int,
    ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUserStore<ApplicationUser, int>, IDisposable
    {
        public ApplicationUserStore()
            : this(new IdentityDbContext())
        {
            base.DisposeContext = true;
        }

        public ApplicationUserStore(DbContext context)
            : base(context)
        {
        }
    }


    public class ApplicationRoleStore
    : RoleStore<ApplicationRole, int, ApplicationUserRole>,
    IQueryableRoleStore<ApplicationRole, int>,
    IRoleStore<ApplicationRole, int>, IDisposable
    {
        public ApplicationRoleStore()
            : base(new IdentityDbContext())
        {
            base.DisposeContext = true;
        }

        public ApplicationRoleStore(DbContext context)
            : base(context)
        {
        }




    }



}

Upvotes: 1

Views: 1794

Answers (1)

jegtugado
jegtugado

Reputation: 5141

Introducing FOREIGN KEY constraint 'FK_dbo.Tickets_dbo.AspNetUsers_UserID' on table 'Tickets' 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.

The cause of this is that you are mapping two foreign keys to a single table.

Refer to this answer. To fix this you should disable the cascade on delete to false on the model builder.

This will disable all cascade deletes on your context:

protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}

UPDATE:

I noticed you are assigning foreignkey IssuedID but you didn't declare it.

public class Ticket
{
    public int? TicketID { get; set; }
    public int UserID { get; set; }
    public int IssuedID { get; set; }

    [ForeignKey("UserID")]
    public virtual ApplicationUser User { get; set; }

    [ForeignKey("IssuedID")]
    public virtual ApplicationUser IssuedUser { get; set; }
}

On your view (Ticket\Index.cshtml):

<th>
    @Html.DisplayNameFor(model => model.IssuedUser)
</th>

<td>
    @Html.DisplayFor(modelItem => item.IssuedUser.FullName) // Or something similar
</td>

Upvotes: 1

Related Questions