I have a table in my EF model that is not creating within the database on access.
The table name is "sites" and is linked to a parent table by the use of a foreign key called "CompanyId".
I am attmempting to list all the sites that belong to a specific company (the company table is linked to the ApplicationUser)
I would expect that when i call the database for a list of the sites that it will be created. However i just receive an error that states the table does not exist
My model for the two tables is as follow
public class Company
{
[Key]
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public string PostCode { get; set; }
public string County { get; set; }
public string Country { get; set; }
public string TelephoneNumber { get; set; }
public string Email { get; set; }
public virtual IQueryable<Site> Sites { get; set; }
}
public class Site
{
[Key]
public int SiteId { get; set; }
public int CompanyId { get; set; }
public string SiteName { get; set; }
public string Url { get; set; }
}
and my controller
public ActionResult Index()
{
//get the user details
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var currentuser = manager.FindById(User.Identity.GetUserId());
// search
var company = currentuser.Companies;
var sites = company.Sites;
if (sites == null)
{
sites = db.Sites.Where(c => c.CompanyId == company.CompanyId);
return View(sites.ToList());
}
return View(company.Sites.ToList());
}
You can see which table is created in your database using Database Manager?
Try
1: Change
public virtual IQueryable<Site> Sites { get; set; }
for
public virtual ICollection<Site> Sites { get; set; }
2: Add property to your site class
public Company Company { get; set; }
Did you create a migration for the change? If not the issue the "Add-Migration whateverYouWant" command in your package manager console.
Do you have automatic migrations enabled? If not then you have to auth the command "update-database" in your package manager console.
Look into your Configuration.cs file under the Migrations folder
and check the Configuration constructor. There should be a property called "AutomaticMigrationsEnabled" set to true in order for this to do what you are expecting.
Related
I'm trying to create 1-to-1 relationship between two classes. 1 user has 1 profile picture and 1 profile picture belongs to one user.
the code is as follows.
public class UserImage
{
[Key, ForeignKey("User")]
public int ImageId { get; set; }
public byte [] ImageContentBytes { get; set; }
public string FileName { get; set; }
public string UserId { get; set; }
public string ImagePath { get; set; }
[InverseProperty("UserImage")]
public virtual ApplicationUser User { get; set; }
}
public class ApplicationUser : IdentityUser
{
public string FullName { get; set; }
public string Address { get; set; }
public string Postcode { get; set; }
public string RoleId { get; set; }
public IdentityRole Role { get; set; }
public int CityId { get; set; }
public ICollection<User_Has_Jobs_Posted> UserJobs { get; set; }
public City City { get; set; } // Adding relationship to the user.
public IList<JobPost> jobPosts { get; set; }
[InverseProperty("User")]
public virtual UserImage UserImage { get; set; }
}
The error is saying:
Unable to determine the principal end of an association between the types 'FinalWorkFinder.Models.UserImage' and 'FinalWorkFinder.Models.ApplicationUser'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
In a one-to-one relationship one entry must depend on another, rather then both entries depending on each other.
So in your case an ApplicationUser entry would be valid on its own but a UserImage cannot.
You can fix this by using the Required attribute on the FK like so:
[Required]
public virtual ApplicationUser User { get; set; }
Or you could use fluent api, and do something along the lines of:
modelBuilder.Entity<ApplicationUser>()
.HasOptional(f => f.UserImage)
.WithRequired(s => s.User);
I am new to Entity Framework and Asp.NET, and therefore, struggling with creating database relationships within the Entity Framework.
I have two SQLite tables (Ticket and User) and have setup my entity models as follows:
public class Users
{
[ForeignKey("id")]
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
}
public class Tickets
{
public int id { get; set; }
public string summary { get; set; }
public string description { get; set; }
public string c_location { get; set; }
public string c_store_device { get; set; }
public string category { get; set; }
public DateTime? created_at { get; set; }
public DateTime? closed_at { get; set; }
public int priority { get; set; }
public int? assigned_to { get; set; }
public DateTime? due_at { get; set; }
public DateTime? updated_at { get; set; }
public string status { get; set; }
public virtual Users Users { get; set; }
}
I am trying to use Entity Framework 7 to export an IEnumerable<Tickets> that includes the User assigned to each Ticket.
I have tried to create my model relationship in MyDBContext as a single User can have multiple Tickets, and also has a foreign key associated in my Sqlite database (Tickets.assigned_to = User.id):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Users - > many Tickets
modelBuilder.Entity<Users>()
.HasMany(p => p.Tickets)
.WithOne(e => e.Users)
.HasForeignKey(p => p.assigned_to);
}
My result ends up with Ticket data being exported, but against every ticket I see a null value for User:
[{"id":10002,...,"Users":null}]
When I use .Include() within my Repository to include each User like this:
public IEnumerable<Tickets> GetAll()
{
return _db.Tickets.Include(t => t.Users).ToList();
}
It results in the error
HTTP Error 502.3 - Bad Gateway
The specified CGI application encountered an error and the server terminated the process.
What I'm trying to retrieve is data that looks like:
{"Ticket";[{"id":10002,..."status":"closed"}],"Users":[{"id":"1"..."email":"johndoe#someplace.com"}]}
I know it probably has something to do with my relationship model, but I cannot work out what I am doing wrong.
First you should really derive your Users from IdentityUser. It helps when trying to wire up the relationship, but I will give you the answer based on your current models. Your ForeignKey property should be on the child entity. By naming conventions, which is what EF uses by default, your public Users Users works better if you put a public int UsersId. Then essentially what EF will do is from your public Users Users it will go to the Users table. Then it looks for the ForeignKey which is set to Id, so now we are in the Users Table looking at the id property. Then it looks for the naming convention UsersId and if it sees it, it will set that property to the value that it saw from the Users Table Id column.
Try using this
public class Users
{
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
}
public class Tickets
{
public int id { get; set; }
public string summary { get; set; }
public string description { get; set; }
public string c_location { get; set; }
public string c_store_device { get; set; }
public string category { get; set; }
public DateTime? created_at { get; set; }
public DateTime? closed_at { get; set; }
public int priority { get; set; }
public DateTime? due_at { get; set; }
public DateTime? updated_at { get; set; }
public string status { get; set; }
[ForeignKey("Id")]
public int UsersId { get; set; }
public virtual Users Users { get; set; }
}
and for your Fluent API configuring
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Users - > many Tickets
modelBuilder.Entity<Users>()
.HasMany(p => p.Tickets)
.WithOne();
}
Now all that does is create the relationship. In order to view the specific items you want to view, use a ViewModel. So, pull the two lists you want from where you want. Then use logic to separate the list how you want them to display.
public class UsersViewModel()
{
public UsersViewModel(Users user, List<Tickets> tickets)
{
this.first_name = user.first_name;
this.last_name = user.last_name;
this.email = user.email;
this.Tickets = new List<Tickets>();
foreach(var ticket in tickets)
{
if(ticket.UserId == user.Id)
{
this.Tickets.Add(ticket)
}
}
}
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public List<Tickets> Tickets { get; set;}
}
then in your controller make your list
public IActionResult Index()
{
var usersList = _repository.Users.ToList();
var ticketsList = _repository.Tickets.ToList();
var model = new List<UsersViewModel>();
foreach(var user in usersList)
{
var listItem = new UsersViewModel(user, ticketsList);
model.Add(listItem);
}
return View(model);
}
or use a Linq query
public IActionResult Index()
{
var usersList = _repository.Users.ToList();
var model = new List<UsersViewModel>();
foreach(var user in usersList)
{
var ticketsList = from x in _repository.Tickets where x.UserId.Equals(user.Id) select x;
var listItem = new UsersViewModel(user, ticketsList);
model.Add(listItem);
}
return View(model);
}
then at the top of your view you should have
#model IEnumerable<UsersViewModel>
public partial class User {
public int Id { get; set; }
public Nullable<int> InvoiceAddress_Id { get; set; }
public Nullable<int> MailAddress_Id { get; set; }
public virtual Address Address { get; set; }
public virtual Address Address1 { get; set; }
}
When I try to retrieve user using Linq and Entity framework, I get;
Invalid column name 'Address_Id1'.
Invalid column name 'Address1_Id1'.
Invalid column name 'Address_Id'.
Invalid column name 'Address_Id1'.
I have no idea why it's coming up like that and doing search for any of these columns in the solution gives nothing! I have a feeling it has something to do with foreign keys.
public partial class Address
{
public Address()
{
this.User = new HashSet<User>();
this.User1 = new HashSet<User>();
}
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public virtual ICollection<Customer> User { get; set; }
public virtual ICollection<Customer> User1 { get; set; }
}
Here is how I'm using entity framework:
CustomDbContext db = new CustomDbContext ();
var user = db.User.First(a => a.Id != 0);
Here's the updated code:
public partial class User
{
public int Id { get; set; }
public Nullable<int> InvoiceAddress_Id { get; set; }
public Nullable<int> MailAddress_Id { get; set; }
public virtual Address InvoiceAddress_ { get; set; }
public virtual Address MailAddress_ { get; set; }
}
Here's the error:
Invalid column name 'Address_Id'.
Invalid column name 'Address_Id1'.
The problem is quite clear: nor your code (attributes, fluent API), neither the EF conventions are configuring the FKs.
If you want to use conventions, you have to adjust the names of the properties and the foreign keys, so that they can be configured. Where you have:
public Nullable<int> InvoiceAddress_Id { get; set; }
public virtual Address Address { get; set; }
You should have:
public Nullable<int> InvoiceAddressId { get; set; }
public virtual Address InvoiceAddress { get; set; }
Note that the FK name is the navigation property name + "Id"
Other option is to implement OnModelCreating of your DbContext and configure the FKs using the fluent API:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasOptional(u => u.Address)
.WithMany();
.HasForeingKey(a => a.InvoiceAddres_Id);
}
Or use the [ForeignKey("")] attribute:
The annotation may be placed on the foreign key property and specify the associated navigation property name, or placed on a navigation property and specify the associated foreign key name
I.e.
[ForeignKey("Address")]
public Nullable<int> InvoiceAddress_Id { get; set; }
or
[ForeignKey("InvoiceAddress_Id")]
public virtual Address Address { get; set; }
Ok so I'm adding on to the Simplemembership.
Model UsersProfiles
namespace OilNGasWeb.Models
{
[Table("Users")]
public class UserProfiles
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Initials { get; set; }
public string Company { get; set; }
public string Department { get; set; }
public string Title { get; set; }
public string Team { get; set; }
public string TeamSub { get; set; }
public string Phone { get; set; }
public string ImageLocation { get; set; }
public string CurrentlyAuthorized { get; set; }
public string Note { get; set; }
public string Comment { get; set; }
//public virtual dbClient Client { get; set; }
public virtual ICollection<Roles> Roles { get; set; } //many to many
public virtual ICollection<dbClient> Clients { get; set; } // many to many
}
}
Roles
namespace OilNGasWeb.Models
{
[Table("webpages_Roles")]
public class Roles
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[Required(ErrorMessage = "Required")]
public int RoleID { get; set; }
[Required(ErrorMessage = "Required")]
public string RoleName { get; set; }
public virtual ICollection<UserProfiles> UserProfiles { get; set; } //many to many
}
}
My issue now that i have it creating the many to many tables like i saw it creat before modifications my question is how to get those tables Renamed
webpages_UsersInRoles
I would prefer not to go into SSMS and change them physically rather tell MVC to use a different instance
From the code above EF produced RolesUserProfiles instead of webpages_UsersInRoles
The error shows when the program is trying to #if (User.IsInRole("Administrator")) validade user.
Naturally I hit F12 on IsInRole to bring me to the definition....
it does but there all empty
Now what ? how can i recode if its hidden from me ? where is the code at , and how can i Modify this?
What i would like out of all this is
either renaming the tables ManytoMany as they are being created
being able to modify the code that looks for webpages_UsersInRoles
Thanks in advance.
You cannot rename the tables. The table names are hard coded in SimpleMembership. You can see the source code here:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/WebMatrix.WebData/SimpleMembershipProvider.cs
Don't use the EF navigational properties. You should be accessing this information via the Membership or WebSecurity API's.
If you really want to do this, then you will need to configure EF to use the tablenames required by simple membership, which means utilizing the fluent mapping syntax.. which is not exactly intuitive.
I have a Project entity and an Rfi entity. The project entity contains a list of TeamMembers. Project is a navigation property in the Rfi entity. In the Rfi entity there is a RecipientId. This Id represents a person from the TeamMembers collection. So imagine, on a web page, we have a drop down box named Recipient. The list includes all team members of the Project. The user will select a Contact from that list. The Id of that contact will be saved in the RecipientsId property. When the page is reloaded we will select the Id of that user in the drop down based off the value in the RecipeintsId property. What is the best way to map this in EF 4.1 using the fluent API?
public class Project : BaseEntity
{
public string ProjectNumber { get; set; }
public string Description { get; set; }
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public string Currency { get; set; }
#region Navigation Properties
public Guid AddressId { get; set; }
public virtual Address Address { get; set; }
public Guid CompanyCodeId { get; set; }
public virtual CompanyCode CompanyCode { get; set; }
public virtual ICollection<Contact> TeamMembers { get; set; }
#endregion
}
public class Rfi : Document
{
public string Number { get; set; }
public string Subject { get; set; }
public string SubcontractorRfiReference { get; set; }
public string SpecificationSection { get; set; }
public RfiStatus RfiStatus { get; set; }
public Guid RecipientId { get; set; }
#region Navigation Properties
public Guid ProjectId { get; set; }
public Project Project { get; set; }
#endregion
}
As I understand it your problem is mapping between Rfi and Contect - Project doesn't have any role in your Recipient functionality from the database perspective.
You need either Recipient navigation property in Rfi or Rfis navigation property in Contact. EF code first needs navigation property on at least one side of the relation.
So you can use something like:
public class Rfi : Document
{
public string Number { get; set; }
public string Subject { get; set; }
public string SubcontractorRfiReference { get; set; }
public string SpecificationSection { get; set; }
public RfiStatus RfiStatus { get; set; }
#region Navigation Properties
public Guid RecipientId { get; set; }
public Contact Recipient { get; set; }
public Guid ProjectId { get; set; }
public Project Project { get; set; }
#endregion
}
And map:
modelBuilder.Entity<Rfi>()
.HasRequired(r => r.Recipient)
.WithMany()
.HasForeignKey(r => r.RecipientId);