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);
Related
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()
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 trying to learn how to use Entity Framework 6 with an already created database, without creating an .edmx file, i.e, using the DbContext and POCO classes.
These are my model classes:
[Table("Category")]
public class Category
{
[Key]
public long CategoryID { get; set; }
public string CategoryName { get; set; }
}
[Table("RegistrationForm")]
public class RegistrationForm
{
[Key]
public int RegistrationID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Country { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
[Table("RegistrationCategory")]
public class RegistrationCategory
{
[Key]
public long RegistrationCategory { get; set; }
public long RegistrationID { get; set; }//Foreign key to RegistrationID in RegistrationForm table in database
public long CategoryID { get; set; }//Foreign key to CategoryID in Category table in database
}
My DbContext class:
public class MyContext : DbContext
{
public virtual DbSet<RegistrationForm> RegistrationForm { get; set; }
public virtual DbSet<Category> Category { get; set; }
public virtual DbSet<RegistrationCategory> RegistrationCategory { get; set; }
}
Here I want to use the default model builder of DbContext.User can select multiple categories in the registration screen so the RegistrationCategory table will have multiple records for each registration. Therefore RegistrationForm and RegistrationCategory are in a one-to-many relationship.
How to write foreign key mappings between the above mentioned models?
How to bind data from Category table data in the mvc view(listbox) so that we can save one record in RegistrationForm table and multiple records in RegistrationCategory table without using loops (using mappings between the c# models) in Entity Framework 6?
The database schema that you have here is a Many to Many relationship between RegistrationForm and Category, with a join table. The RegistrationCategory Table is not necessary to be modeled in Entity Framework at all. You will need to use Entity Framework Fluent API to generate the correct mappings.
First, your RegistrationForm Table:
public class RegistrationForm
{
[Key]
public int RegistrationID { get; set; }
...
// add a navigation property ICollection<Category> to reference the categories
public virtual ICollection<Category> Categories { get; set; }
}
Next, the Category class:
public class Category
{
[Key]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
//Navigation property to reference the RegistrationForms
public virtual ICollection<RegistrationForm> RegistrationForms { get; set; }
}
next, in your DbContext: note the change in pluralization, and the removal of the RegistrationCategory, you do not need a model class for it at all.
public class MyContext : DbContext
{
public virtual DbSet<RegistrationForm> RegistrationForms { get; set; }
public virtual DbSet<Category> Categories { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<RegistrationForm>()
.HasMany(r => r.Categories)
.WithMany(c => c.RegistrationForms)
.Map(
m =>
{
m.MapLeftKey("RegistrationID");
m.MapRightKey("CategoryID");
m.ToTable("RegistrationCategory");
}
);
}
With this in place, you can now query all the Categories of a RegistrationForm or all the RegistrationForms of a Category.
foreach (var category in registrationForm.Categories)
{
//do whatever with each category
}
I'm trying to create a linked table that will allow me to have a many to many relationship between my product and accessory tables.
My classes are like this:
public class Product {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Accessory> Accessories { get; set; }
}
public class Accessory {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Machine> Machine { get; set; }
}
public class Type {
public int Id { get; set; }
public string Name { get; set; }
}
The same accessory can be on a product more than once if it is a different type, which will be determined in the link table. Something like this:
public class ProductAccessoryLink {
public int productId {get; set;}
public int accessoryId {get; set;}
public int typeId {get; set}
public int sort {get; set;}
public string notes {get; set}
}
Is this the right approach.
EDIT
This is the error I'm getting when I run update-database:
Introducing FOREIGN KEY constraint
'FK_dbo.ProductAccessoryLinks_dbo.Types_TypeId' on table
'ProductAccessoryLinks' 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.
This is the sql causing the error: ALTER TABLE
[dbo].[ProductAccessoryLinks] ADD CONSTRAINT
[FK_dbo.ProductAccessoryLinks_dbo.Types_TypeId] FOREIGN KEY ([TypeId])
REFERENCES [dbo].[Types] ([Id]) ON DELETE CASCADE
In your case you need to map explicitly the junction table. Your model would be like this:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductAccessoryLink> ProductAccessoryLinks { get; set; }
}
public class Accessory
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductAccessoryLink> ProductAccessoryLinks { get; set; }
}
public class Type
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ProductAccessoryLink
{
public int ProductId { get; set; }
public int AccessoryId { get; set; }
public int TypeId { get; set; }
public int sort { get; set; }
public string notes { get; set; }
public virtual Type Type { get; set; }
public virtual Product Product { get; set; }
public virtual Accessory Accessory { get; set; }
}
And you could configure the relationships overriding the OnModelCreating method on your context this way:
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductAccessoryLink>().HasKey(i => new { i.ProductId, i.AccesoryId, i.TypeId});
modelBuilder.Entity<ProductAccessoryLink>()
.HasRequired(i => i.Product)
.WithMany(k => k.ProductAccessoryLinks)
.HasForeignKey(i=>i.ProductId);
modelBuilder.Entity<ProductAccessoryLink>()
.HasRequired(i => i.Accesory)
.WithMany(k => k.ProductAccessoryLinks)
.HasForeignKey(i=>i.AccesoryId);
modelBuilder.Entity<ProductAccessoryLink>()
.HasRequired(i => i.Type)
.WithMany()
.HasForeignKey(i=>i.TypeId);
}
EF lets you configure directly many-to-many relationships of the way you were attempting to. Thereby EF is responsible for build a join table in the database with the appropriate keys of the tables it’s joining. (The keys are both primary keys of the join table and foreign keys pointing to the joined tables). That lets you to get your data across the join table without you having to be aware of its presence. But when you want to personalize that table (adding, for example, some additional properties), you need to map it explicitly as I show above.
Update
That exception is caused when you have multiple paths of cascade deletes that could end trying to delete the same row in the Types table. To resolve that problem I recommend you check my answer in this post
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