Entity Framework Annotation with two tables pointing at each other - c#

I am trying to use CodeFirst to generate my database.
I have two tables Staff and Team, There is one Team Leader in each team that is a foreign key to a staffID, and each staff is associated to one Team.
public class Staff
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string PasswordHash { get; set; }
public string Salt { get; set; }
public string Token { get; set; }
public string Mobile { get; set; }
public string Email { get; set; }
public bool Admin { get; set; }
public bool Active { get; set; }
public int TeamID { get; set; }
[ForeignKey("TeamID")]
public Team Team { get; set; }
}
public class Team
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int TeamLeaderID { get; set; }
[ForeignKey("TeamLeaderID")]
public Staff TeamLeader { get; set; }
}
Because each one is pointing to the other I get an error Unable to determine the principal end of an association between the types 'Team' and 'Staff'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations. How do I annotate it in such a way that it understands why I am doing this.

Think about it this way... what comes first the team or the team leader? If you try to create a team leader you can't because you have to first specify a team! But if you want to create a team you can't because you must specify who the team leader is according to your foreign key constraints.
You will have to ease up in some way and either make it so that a team can have an optional team leader, or a staff member can optionally belong to a team.
You do this by changing one of the foreign key IDs to a nullable type:
public int? TeamLeaderID { get; set; }

Your code seems like you are trying to include business rule enforcement/responsibility via referential integrity. You have a one to many relationship your Team -> Staff. You just add a boolean for the TeamLeader. Your logic before doing a database write should check to see if you have an existing TeamLeader or not already.
public class Staff
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string PasswordHash { get; set; }
public string Salt { get; set; }
public string Token { get; set; }
public string Mobile { get; set; }
public string Email { get; set; }
public bool Admin { get; set; }
public bool Active { get; set; }
public IsTeamLeader { get; set; }
}
public class Team
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
//virtual keyword tells Code First to create the proper Foreign Key relationship
public virtual List<Staff> Members{ get; set; }
}
If you had a large system, with many developers, you could use the fluent API to accomplish your goal and enforce your team leader rule at the database level, thus preventing an out of touch developer from inadvertently adding a second team leader to any give team but if this is a small to normal size project, with small teams that are aware of the basics of the company/project than a simple one to many relationship will accomplish the mission and you can rely on your business rules/logic to enforce/protect the database data so that there is one team leader for any given team at any give time. Consider an AddUpdateTeamMember type method that is called by everyone that enforces the team leader requirement. A stored procedure is another great way to easily solve this problem if you are still considering a model first approach and still experimenting with code first.
Consider too, what if there was a need for two team leaders on one team at some future point of time in the project, database might get too inconveniently "locked down" to scale to this change.

Related

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.

What is the Proper Way To Configure a Multi Tenancy with Shared Schema in EF Core

I'm working on designing a multi-tenant application. I have a Tenant entity, User entity, and multiple other entities that have a TenantId property.
I started adding child references to my Tenant entity, but looking at other code examples leads me to believe that this isn't the "correct" way to get the child entities to properly register the TenantId foreign key. However, if I don't add the child collections to my Tenant entity, the migrations don't register the TenantId foreign key to the children.
What is the correct (or suggested) way to manage these relationships in a Shared Schema Multi-Tenant pattern?
For example, suppose I have a Tenant with Users that all have access to Taxis, Garages, and Zones within their Tenant.
Note: I'm using a base class in my real code, but decided that would complicate the example so I intentionally spelled everything out.
public class Tenant
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<User> Users { get; set; }
// Should the below properties be left out?
public ICollection<Taxi> Taxis { get; set; }
public ICollection<Garage> Garages { get; set; }
public ICollection<Zone> Zones { get; set; }
}
public class User
{
public long Id { get; set; }
public long TenantId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public class Taxi
{
public long Id { get; set; }
public long TenantId { get; set; }
public string Name {get; set; }
}
public class Garage
{
public long Id { get; set; }
public long TenantId { get; set; }
public string Name { get; set; }
}
public class Zone
{
public long Id { get; set; }
public long TenantId { get; set; }
public string Name { get; set; }
}
In case you will have a Tenant as a virtual property in the models like the one given below,
public class User
{
public long Id { get; set; }
public long TenantId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public virtual Tenant TenantDetails {get;set;}
}
you might be required to get all the dependent entity written under a tenant.
However, if that is not the case, you don't have to use the dependent entity as the child under the Tenant Entity. Normally, we consider tenant to be a metadata of the application or a higher level domain object. The remaining entities like the business objects can have a Tenant property to identify the tenant detail for the record, but IMHO, the vice-versa is not required on a realtime use rather from an EF modelling standpoint.

Asp.net code first many to one

Well it's a noob question but i can't figure out the solution.
I have two entities, user and team. User can create a team and invite other users. User can belong only one team but team has multiple users.
What would be the most correct relationship between users and team? I also need DateJoin in team and other properties. Should i create third table(TeamMembers)?
Here is code what i tried :
public class TeamMember
{
public int Id { get; set; }
[ForeignKey("Team")]
public int TeamId { get; set; }
public Team Team { get; set; }
[ForeignKey("User")]
public string UserId { get; set; }
public User User { get; set; }
public DateTime DateJoin { get; set; }
public RoleEnum MemberRole { get; set; }
}
public enum RoleEnum
{
Capitan = 1,
Main,
Sub
}
And team has list of members:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public int Score { get; set; }
public ICollection <TeamMember> Members { get; set; }
}
But third table means many to many relationship...
If the user can only belong to one team then this is the correct format.
However, if you think you might change this policy in the future then I do suggest you use a many to many relationship. This would also allow you to keep track of the previous teams your users belonged to, by simply using a "DateLeave" property for example.

Unable to determine the principal end of an association - Entity Framework Model First

I have created Entity Data Model in Visual Studio. Now I have file with SQL queries and C# classes generated from Model.
Question:
Classes are generated without annotations or code behind (Fluent API). Is it OK? I tried to run my application but exception was thrown:
Unable to determine the principal end of an association between the types 'Runnection.Models.Address' and 'Runnection.Models.User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I read that I can not use Fluent API with "Model First". So what can I do?
Code:
User
public partial class User
{
public User()
{
this.Events = new HashSet<Event>();
this.CreatedEvents = new HashSet<Event>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Photo { get; set; }
public int EventId { get; set; }
public string Nickname { get; set; }
public OwnerType OwnerType { get; set; }
public NetworkPlaceType PlaceType { get; set; }
public virtual ICollection<Event> Events { get; set; }
public virtual Address Address { get; set; }
public virtual ICollection<Event> CreatedEvents { get; set; }
public virtual Owner Owner { get; set; }
}
Address
public partial class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
Context
//Model First does not use this method
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>().HasRequired(address => address.User)
.WithRequiredDependent();
modelBuilder.Entity<User>().HasRequired(user => user.Address)
.WithRequiredPrincipal();
base.OnModelCreating(modelBuilder);
}
You have to specify the principal in a one-to-one relationship.
public partial class Address
{
[Key, ForeignKey("User")]
public int Id { get; set; }
public string Street { get; set; }
public string StreetNumber { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string Country { get; set; }
public virtual User User { get; set; }
}
By specifying a FK constraint, EF knows the User must exists first (the principal) and the Address follows.
Further reading at MSDN.
Also, see this SO answer.
Updated from comments
In the designer, select the association (line between Users & Address). On the properties window, hit the button with the [...] on Referential Constraint (or double click the line). Set the Principal as User.
Error:
Had same error of "Unable to determine the principal end of an association between the types 'Providence.Common.Data.Batch' and 'Providence.Common.Data.Batch'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.".
HOWEVER, note that this is the SAME table.
Cause: My database was MS SQL Server. Unfortunately when MS SQL Server's Management Studio adds foreign keys, it adds the default foreign key as Batch ID column of Batch table linking back to itself. You as developer are suppose to pick another table and id to truly foreign key to, but if you fail to it will still allow entry of the self referencing FK.
Solution:
Solution was to delete the default FK.
Cause 2: Another situation is that the current table may be fixed but the old historical image of the table when the EF's edmx was done had the default FK.
Solution 2: is to delete the table from the Model Browser's Entity Types list and click "yes" and then "Update Model from the Database" again.

Many to Many self Join with Entity Framework Code First

Consider this Poco:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
}
Now i want to implement a follow technique where a user may follow other users so basically its self Many to Many relationship
problem is i don't know how exactly i can achieve this in Entity Framework Code-First ?
I thought of a linker Table :
public class UserFollow
{
public int Id { get; set; }
public int Follower { get; set; }
public int Following { get; set; }
public DateTime FollowDate { get; set; }
}
i want to be able to get All Followers and Following from every User Object?
This is quite simple using EF code-first as you only need the User POCO:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
public ICollection<User> FollowedUsers { get; set; }
}
The collection means that a User is related to other users.
PS: I noted you added a timestamp in your solution example. To achieve that you should still add the collection changing the generic type to whatever suits your needs.
Hope it helps.

Categories

Resources