Can someone guide me on how to construct the proper property navigation on the below tables?
I have these tables in my database:
I then need to relate the Status table to get the status Name on every table
These are my model classes:
[Table("Companies")]
public class CompanyEntity
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int Status_Id { get; set; }
public DateTime Created_Date { get; set; }
public DateTime Updated_Date { get; set; }
[ForeignKey("Status_Id")]
public Status Status { get; set; }
}
[Table("Customers")]
public class CustomerEntity
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int Status_Id { get; set; }
}
[Table("Status")]
public class Status
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public Company Company { get; set; }
}
My goal is to when I get all the Companies or Customers using DBContext e.g. var companies = _dbContext.Companies.ToList(). I want to get the status of every record for Companies and Customers. I'm not so sure how to construct the navigation property properly for the said models.
TIA!
Update #1
After following the below suggestion, yes the Status is not NULL anymore. But, it gets the wrong status id. Instead of using the Status_Id, it uses the Id of the Company. Please see below snippets. The status of the said company is 6.
But if you notice on the 2nd snip, the status is 3 which is the Id of the Company.
I also have this code in OnModelCreating.
modelBuilder.Entity<Company>()
.HasOne<Status>()
.WithMany()
.HasForeignKey(p => p.Status_Id);
This is the reason why I get that behavior. But if I removed this, the Status property is gets NULL.
Update #2
Just fixed my issue. I need to change the Company property from public Company Company { get;set; } to public List Companies { get;set; }. Then add the suggested answer Include`.
[Table("Status")]
public class Status
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public List<Company> Companies { get; set; }
}
You have to add the .Include() method to join your status table in your result like so:
_dbContext.Companies.Include(c => c.Status).ToList()
Related
I am using Webapi and i have two tables in database and Department and Info tables. Department table has relation with Info table. I am using entity framework to retrieve data from database but I am getting data from only one table INFO so the department table shows NULL it has to show department data because both have relation.
Without Webapi the code is working fine. So where I am wrong and why does not Department table show in webapi.
I hope you understand my question thanks.
Contorller
public class WebApiController : ApiController
{
[HttpGet]
public IHttpActionResult EmployeeList()
{
var List = DB.Infoes.ToList().OrderByDescending(x => x.ID);
return Json(List);
}
}
Model
public partial class Info
{
public int ID { get; set; }
public string Image_Name { get; set; }
public string First_Name { get; set; }
public string Last_name { get; set; }
public string Desription { get; set; }
public Nullable<int> DeprtmentIDFK { get; set; }
public virtual Department Department { get; set; }
}
public partial class Department
{
public int DepartmentID { get; set; }
public string DepartmentName { get; set; }
public virtual ICollection<Info> Infoes { get; set; }
}
As it is discussed here, in order to fetch navigation properties you have to Include them in your IQueryable, otherwise you always get null values.
I am using Entity Framework Core 2.0.1 and I have the following models
public class Article
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string Slug { get; set; }
public int Approved { get; set; }
public DateTime ArticleDate { get; set; }
// ... some other fields
public virtual ICollection<ArticleCategoryRelation> ArticleCategoryRelations { get; set; }
}
public class ArticleCategory
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
//... soem other fields
[ForeignKey("ArticleCategoryParent")]
public int? ArticleCategoryParentID { get; set; }
public virtual ArticleCategory ArticleCategoryParent { get; set; }
public virtual ICollection<ArticleCategory> SubCategories { get; set; }
public virtual ICollection<ArticleCategoryRelation> ArticleCategoryRelations { get; set; }
}
public class ArticleCategoryRelation
{
[Column(Order = 0)]
public int ArticleId { get; set; }
public Article Article { get; set; }
[Column(Order = 1)]
public int ArticleCategoryId { get; set; }
public ArticleCategory ArticleCategory {get; set;}
}
Every article belongs to one or more categories. Categories might have parent category.
I want to get from database last two articles (where Approved = 1) with related category details, for each category that belongs to a parent category which id is given as input.
I have tried but with no success. I can't filter results of an .Include() entity. Is it possible... or I don't know how to do it?
All my data are accessed through entity framework with appContext (the context used to get entities from database). Can I achieve what I want through entity framework core (lambda expression is preferred over Linq if possible), or should I use ADO.NET library (which I know how to execute custom queries).
P.S. I want to get data only to show in the view... no edit is needed.
You don't actually need to include here at all, as far as I can tell. Whenever you use data from a nav property, EF will go get the data from that table, as best it can filter it.
var CategoriesUnderParent = AppContext.ArticleCategories
.Where(c => c.ArticleCategoryParent == {parent});
foreach(var category in CategoriesUnderParent)
{
var ArticlesAllowed = category.ArticleCategoryRelations
.Where(acr => acr.Article.Approved == 1).Select(a => a.Article);
var ArticlesPicked = ArticlesAllowed
.OrderByDescending(ar => ar.ArticleDate)
.Take(2);
// Do something with your data
}
I have two entities in database: customer and user and building a one-to-many relationship between them, so 1 customer -> many users.
This is my customer model:
public class Customer
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public ICollection<User> Users { get; set; }
}
What would be the correct User model, I mean with Customer property and CustomerId property or just CustomerId? So this:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public Customer Customer { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
}
.. or this?:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
}
Actually it should be like the code example below. You should specify what is local primary key, remote key and if there is navigation property (Customer), then You should specify "How should it recognize the object" => based on the this or that key of Customer (CustomerId).
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//other properties
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
public int CustomerId { get; set; }
}
If You are not interested in having navigation property, You can simply avoid that to have only:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//other properties
public int CustomerId { get; set; }
}
More info can be found there: http://www.entityframeworktutorial.net/code-first/foreignkey-dataannotations-attribute-in-code-first.aspx
Note: You do not need to specify [ForeignKey] attribute, if You are using Navigation Property with the same name (e.g. Customer & CustomerId).
If there are multiple references to the same class (e.g. You have User that will have exactly 2 Customers (CustomerA, CustomerB), then You must specify following:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//other properties
[ForeignKey("CustomerIdA")]
public Customer CustomerA { get; set; }
public int CustomerIdA { get; set; }
[ForeignKey("CustomerIdB")]
public Customer CustomerB { get; set; }
public int CustomerIdB { get; set; }
}
In the first case you have a correctly set navigational property between User and Customer. In the second case, you cannot navigate from User to Customer, and you have a Foreign Key attribute that point to a non-existent property.
You should, however, invert the order of the ForeingKeyAttribute to make it clearer (both ways are OK, though):
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
public int CustomerId { get; set; }
If you won't need User.Customer, you can skip setting up the navigational property altogether. The same applies to Customer.Users, you can skip setting up that navigational property if it's not needed.
I currently have an employee model
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<StateLicenseType> Licenses { get; set; }
and a License Type Model
public class StateLicenseType
{
public int StateLicenseTypeId { get; set; }
public string State { get; set; }
public string LicenseName { get; set; }
public virtual Employee Employee { get; set; }
}
This relationship can be one to many, but I also need to add some information to the license when saved. I need to be able to store the employees unique license number and have not been able to find out how to do this while searching around. Is there a way to have Entity Framework add a column to a join table and then even if I have to, update it myself?
Is there a better/different way to model this relationship with EF?
In an old DB the table was created like this,
CREATE TABLE `nmlsstatelicenses` ( `peopleid` int(11) DEFAULT NULL, `statelicensetypeid` int(11) DEFAULT NULL, `licensenumber` varchar(25) DEFAULT NULL)
You need to create a third entity which will be a linking entity (like a linking table in many-to-many relationships in database. Here is an example: many-to-many relationships with additional information.
So you would have the following entities in your model:
public Employee
{
public string EmployeeId { get;set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<LicenseRegistration> RegisteredLicenses { get; set; }
}
public LicenseType
{
public int StateLicenseTypeId { get; set; }
public string State { get; set; }
public string LicenseName { get; set; }
public virtual ICollection<LicenseRegistration> RegisteredLicenses { get; set; }
}
public LicenseRegistration
{
//properties for the additional information go here
/////////////////////////////////////////////////////
public int EmployeeId {get;set;}
[ForeignKey("EmployeeId")]
public Employee Employee {get;set;}
public int LicenseTypeId {get;set;}
[ForeignKey("LicenseTypeId")]
public LicenseType {get;set;}
}
Then, in your DBContext file, you will need to define 1-to-many relationship between Employee and LicenseRegistration, and between LicenseType and LicenseRegistration.
Hope this helps!
UPDATE
Here is how you would set up the relationships:
modelbuilder.Entity<LicenseRegistration>()
.HasRequired(lr => lr.LicenseType)
.WithMany(lt => lt.RegisteredLicenses)
.HasForeignKey(lr => lr.LicenseTypeId);
modelbuilder.Entity<LicenseRegistration>()
.HasRequired(lr => lr.Employee)
.WithMany(e => e.RegisteredLicenses)
.HasForeignKey(lr => lr.EmployeeId);
Forewarning: I know approximately nothing when it comes to MVC/Entity Framework/Linq queries.
I'm having an issue when I try to query the database. Here's the query I'm using:
int? UserId = db.StudentModel
.Where(c => c.UserName == certUserName)
.Select(c => c.UserId)
.FirstOrDefault();
When it searches the database, it successfully retrieves the UserId.
The problem is that I then use the following query:
CompletionsModel student = db.Completions.Find(UserId);
When I do this, it throws an inner exception that states
{"Invalid column name 'UserProfile_UserId'."}
The weird thing is that when I go to my code and mouse over the 'db' part of the command to see what data it's holding, it has CourseModel, StudentModel, and Completions (though the model's actual filename is CompletionsModel - is that a clue?), so it seems like they're linked properly.
Here's the code for my three models and the database context.
CompletionsModel (UserProfile is white text in my code; not sure why it's teal here Same with UserId and CompletionDate):
[Table("Completion")]
public class CompletionsModel
{
[Key]
public int UserId { get; set; }
public string PRD_NUM { get; set; }
public DateTime CompletionDate { get; set; }
public virtual CourseModel PRD { get; set; }
public virtual StudentModel UserProfile { get; set; }
}
CourseModel:
[Table("PRD")]
public class CourseModel
{
[Key]
public string PRD_NUM { get; set; }
public string PRD_TIT { get; set; }
//because any number of students can be enrolled in one course
public virtual ICollection<CompletionsModel> CompletionsModel { get; set; }
}
StudentModel:
[Table("UserProfile")]
public class StudentModel
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<CompletionsModel> CompletionsModel { get; set; }
}
DBContext:
public class ClassContext : DbContext
{
public ClassContext()
: base("DefaultConnection")
{
}
public DbSet<StudentModel> StudentModel { get; set; }
public DbSet<CompletionsModel> Completions { get; set; }
public DbSet<CourseModel> CourseModel { get; set; }
}
And finally, an image of my database layout - maybe this will help things along, too:
I'm too at the beginning of Entity Framework, but what does irritate me is, that you have kind of foreign key relationship between Completion and UserProfile, without really defining, a int column as foreign key in your Completion Table.
You could try to change
public virtual StudentModel UserProfile { get; set; }
to something like
public virtual int StudentId { get; set; }
[ForeignKey("StudentId")]
public virtual StudentModel UserProfile { get; set; }
The same for PRD
But maybe a change in your database is not what you want.
What you could also do, is to remove these lines
public virtual CourseModel PRD { get; set; }
public virtual StudentModel UserProfile { get; set; }
Hope that helps.
EDIT:
I guess the problem is, that you are missing the ForeignKey Attribute at your UserProfile property in your Completions table.
So use
[ForeignKey("UserId")]
public virtual StudentModel UserProfile { get; set; }
instead of
public virtual StudentModel UserProfile { get; set; }
if the UserIds are representing the same user