Modeling Employee-Assistant(s) relationship with EF Code First - c#

Here are the business requirements, in short:
All employees need to be stored in a database
Some employees have assistants, some do not
Some employees have more than one assistant
Assistants are employees, as well
There is obviously a bit of a self-referencing situation. But the difference from a typical "Employee-Manager" situation is that here one Employee can have 0 or multiple assistants. So, the combination of Employee and employee's Assistants needs to be stored in a separate table in a one-to-many relationship between Employee and EmployeeAssistant. But I'm getting confused how to model this in Entity Framework 6 Code First.
I started with this:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class EmployeeAssistant
{
[ForeignKey("Employee")]
public int EmployeeId { get; set; }
public virtual Employee Employee { get; set; }
[ForeignKey("Assistant")]
public int AssistantId { get; set; }
public virtual Employee Assistant { get; set; }
}
But I get an error during Update-Database command:
Introducing FOREIGN KEY constraint 'FK_dbo.EmployeeAssistant_dbo.Employee_EmployeeId' on table 'EmployeeAssistant' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
What am I missing? Should I approach this differently?

since each employee may have one or more assistants (and each assistant will have one or more employees) and all are employees, the simplest solution is one class with two collections for assistants and employees, and the relations will be managed by the framework:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<Employee> Assistants { get; set; }
public ICollection<Employee> Employees { get; set; }
}
when you use package manager console to add migration it will automatically create two tables, one for employees, and another for many to many relations.
then all you have to do is to find related assistants and/or employees by using Include extension method.
db.Employees.Where(x=>x.Id==id).Include(x=>x.Assistants).FirstOrDefault()
and/or
db.Employees.Where(x=>x.Id==id).Include(x=>x.Employees).FirstOrDefault()

Based on this link Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why?
It seems if you delete an EmployeeAssistant with your code, it causes two cascading delete paths.
I would suggest a structure such as this:
After edit
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<EmployeeAssistant> Assistants { get; set; } //if an employee has no assistants this List can easily just be empty
OR
public ICollection<EmployeeAssistant> Assistants { get; set; } // depending on your architecture, choose the one that would suit you better
}
public class EmployeeAssistant
{
[ForeignKey("Employee")]
public int EmployeeId { get; set; } //this is the employee who 'has' this assistant
public virtual Employee Employee { get; set; }
public int Id { get; set; } //this is the assistant's own information - identical to employee's basic info
public string FirstName { get; set; }
public string LastName { get; set; }
}
After a while of brain-boggling, I even came up with a possibility where you just need 1 class, Employee, but it includes a bool IsAssistant denoting if this employee is an assistant, and AssistantEmployeeId which is an employee ID of the employee who 'has' this assistant.
For example:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsAssistant { get; set; }
public int EmployeeAssistantID { get; set; }
}
I know this second method is very messy and probably doesn't suit your needs, but personally I always create database tables first then do 'Generate Model from Database' so I'm inexperienced at code-first approach.

Related

Is there any way to embed a class Element into a class Element in Entity Framework?

This is my code:
namespace MyProject.Models.Database
{
public class Recipe
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
public string? Description { get; set; }
public string? Picture { get; set; }
public int Worktime { get; set; }
public int? Cooktime { get; set; }
public int Difficulty { get; set; }
public int Portions { get; set; }
public List<Ingredient> Ingredients { get; set; }
}
public class Ingredient
{
public Guid Id { get; set; } = Guid.NewGuid();
public Guid IngredientId { get; set; }
public int Qty { get; set; }
public string QtyUnit { get; set; }
}
}
I want the class "Recipe" to include many elements of type "Ingredient". Ive read stuff about One-to-One and Many-To-Many but i just dont get it...
any Ideas?
thx
One recipe can consist of many ingredients, one ingredient can also be in many recipes. This is a many-to-many relationship.
What you need to do is create a new class that contains Id, RecipeId, IngredientId.Name that class something like RecipeIngredient. When you are creating a DbSet<RecipeIngredient> in your db context, name your table RecipesIngredients.
What should be the data types of the properties in RecipeIngredient?
The Id property will be the primary key, you can decide the data type.
RecipeId will be a foreign key for the Recipe, so it needs the same data type as the primary key of the Recipe (in your case Guid).
IngredientId will be the foreign key for the Ingredient, so the data type will again be Guid in your case.
Note that instead of putting Id in your RecipeIngredient, you can create a composite key instead.
When should you do that? -> here
I suggest you learn about the different relationships and how to apply them using C# and Entity Framework Core -> here
Good luck on your learning journey! When you don't feel you understand a topic, don't worry and don't get discouraged, you just need more experience. Keep up the good work :)

EF 6 getting parent record from DB when table has many to many relation with itself

I am trying to build an organization hierarchy where each team might contain one or many members and/or one or many sub-teams.
To do so, my model is:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Members { get; set; }
public virtual ICollection<Team> SubTeams { get; set; }
public Employee Manager { get; set; }
}
When adding a migration and updating database, everything seems logical in the table.
EF has added an extra nullable column "Team_Id" where the Id of the parent Team gets stored.
My question is about getting the Id of the parent Team from my model.
I tried adding:
public int? Team_Id
To my model, but EF considered it as a model change and asked for another migration.
How can I get the value of column Team_Id in my model? getting this info takes too much processing when looping through teams.
I always add foreign key in my model. When it adds to the model, EF won't add Team_Id .
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Members { get; set; }
public virtual ICollection<Team> SubTeams { get; set; }
public Employee Manager { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public Team ParentTeam { get; set; }
}
I hope this example be helpful.

Entity Framework Code First "join table"

I am working with Entity Framework Code First.
I have an Entity Called Notes
I also have other Entities such as
BusinessPartners
Opportunities
WorkOrders
All of these entities may have notes.
What is the best way to model this
1.) in the notes table have optional foreign keys to Business partners, Opportunities, and workorders. Then just set the optional key to which the note is related
2.) have intermediate tables such as BusinessPartnerNotes, with two field BusinessPartnerId and NoteId
It should be mentioned that a note is never going to be related to two entities at the same time.
Any help or suggestions would be appreciated.
Given your description of the cardinalities, and assuming Notes for BusinessPartners have the same format of Notes for Opportunities, I'd go with the simplest approach (option 1. in your list).
class Note
{
public int Id { get; set; }
public string Content { get; set; }
}
class BusinessPartner
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Note> Notes { get; set; }
}
class Opportunity
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Note> Notes { get; set; }
}
Which should generate the following tables:
Notes
Id
Content
BusinessPartner_Id
Opportunity_Id
BusinessPartners
Id
Name
Opportunities
Id
Name

Adding Extra Column to join table

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);

2 POCO's with inheritance creates one table instead of two

I am creating a fairly simplistic Database for a holiday system.
Entities
Employee
public class Employee
{
public int Id { get; set;}
public string Username { get; set; }
public LineManger Manager { get; set; }
}
LineManger
public class LineManager : Employee
{
public string CompanySection { get; set; }
}
Relationship
As you can see, each employee has one LineManger however an Employee could be a LineManager.
In my DbContext I have:
public DbSet<Employee> Employees { get; set; }
public DbSet<LineManager> Managers { get; set; }
public DbSet<HolidayConfiguration> Configurations { get; set; }
public DbSet<Holiday> Holidays { get; set; }
When I ran PM > Update-Database -verbose for the first time it only created an Employee table and this table has CompanySection and Manager_Id which doesn't map to anywhere seeing as there isn't a LineManager table.
Any explanations on why this has happened? Is this correct?
It has to be like this, because every LineManager is an Employee, so when you are querying Employees you are also looking for LineManager. DbSet<Employee> Employees matches only one table, so the only way how EF can create table is to put in it all fields from LineManager.
Sometime (when you have more inhertiance) EF create special column in which it puts class name.

Categories

Resources