Reputation: 1068
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.
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
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