Entity Framework One-To-Many issue - c#

I use Entity Framework in my project. I stuck in some trouble.
I have two classes. Here are they:
public class User
{
public virtual Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual string Username { get; set; }
public string Email { get; set; }
public virtual Company Company { get; set; }
}
public class Company
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Requisites { get; set; }
public virtual List<User> Workers { get; set; }
}
Also I have repo. So when I create a new user and I want to add this user to company.
How should I implement that? I have two ways:
user.Company = company;
company.Workers.Add(user);
Which way is preferable?

If company is already attached to the context.
Either
var company = db.Set<Company>().Find(companyId);
or
db.Set<Company>().Attach(company);
user.Company = company;
In the first case, if you only do that. The user will not be added to the database, you need to have this too.
db.Entry(user).State = EntityState.Added;
or
db.Set<User>().Add(user);
Then user will be added and will have relationship with company.
company.Workers.Add(user);
This one only should be okay, the user will be added and have relationship with company. But be careful if Workers is null, you need to instantiate it first.

Related

NET Core identity grouping of users

I currently have a project that uses identity and individual users have access to their own resources (sub database table linked by application user id). I'd like each user who signs up (admin) to then be able to invite new users to their 'group' and all share the same resource.
I'm looking at implementing a 'Groups' and 'UserGroups' table similar to the current 'Roles' and 'UserRoles' tables. Does the following code look ok to achieve this?
public class ApplicationUser : IdentityUser
{
[MaxLength(30)]
public string FirstName { get; set; }
[MaxLength(30)]
public string LastName { get; set; }
[MaxLength(100)]
public string Company { get; set; }
[MaxLength(30)]
public string Telephone { get; set; }
[MaxLength(15)]
public string Postcode { get; set; }
public DateTime Created { get; set; } = DateTime.UtcNow;
public DateTime PasswordResetTime { get; set; } = DateTime.UtcNow;
public bool PasswordReset { get; set; } = false;
public virtual ICollection<GSMSite> GSMSites { get; set; }
}
public class UserGroups
{
public virtual ApplicationUser ApplicationUser { get; set; }
public virtual Groups Groups { get; set; }
}
public class Groups
{
public Guid Id { get; set; }
[MaxLength(30)]
public string Name { get; set; }
}
You are trying to achieve Many to Many relationship.
Firstly by convention You should name Classes with singular form:
UserGroups -> UserGroup
Groups -> Group
You should also put ICollection<UserGroup> in both AplicationUser and Group:
public virtual ICollection<UserGroup> UserGroups
And change UserGroup to:
public class UserGroup
{
public Guid ApplicationUserId { get; set;}
public virtual ApplicationUser ApplicationUser { get; set; }
public Guid GroupId { get; set; }
public virtual Groups Groups { get; set; }
}
And then the resource You are talking about should be linked to Group not ApplicationUser.

How to join two or more tables using Entity Framework in ASP.NET MVC?

I am looking to join 3 tables together using entity framework, dependency injection and with SQLite.
So far I have this:
using System.Collections.Generic;
using System.Linq;
namespace MMS.Data.Models
{
public class User
{
public int Id { get; set; }
//Role of user
public Role Role { get; set; }
// first name of user
public string Name { get; set; }
// Date of birth
public string DOB { get; set; }
public string Gender { get; set; }
public string Address { get; set; }
//Telephone number
public string MobileNumber { get; set; }
//email address
public string EmailAddress { get; set;}
// EF Relationship - a user can have many bookings
public IList<Booking> Bookings { get; set; } = new List<Booking>();
}
public class Booking
{
public int Id { get; set; }
// name of reviewer
public string Name { get; set; }
// date review was made
public DateTime CreatedOn { get; set; }
// reviewer comments
public string Comment { get; set; }
// EF dependent relationship booking belongs to a user
public int UserId { get; set; }
// Navigation property
public User User { get; set; }
}
}
In terms of the services folder, I am okay with that. The thing that is bugging me is how do I create an 3rd table model and have it combined with the other two.
For example, I want the users to able to make bookings, and an admin able to come in and look and add users, delete bookings etc. This bit I understand.
How do I hook up an employee to able to look at the booking and the person etc? I hope I explained this correctly. Essentially a third table where employees can be created and pull the information of the user and the booking?
I know I could technically do this without a third table as I could just continue on and allow a user to have access to all the bookings and user information. However, I do want a certain types of employees can only see what they need to see.
Can anyone help?
This way employee will be binded to User table. You can access which employee makes the booking or you can just modify it.
Basically public IList<YourModel> Model {get;set;} needs to be annoated in YourModel as public YourModel YourModel{get;set;}
Below is an example:
public class Employee
{
public string Role { get; set;} // any property
public IList<User> Users { get; set;}
}
public class User
{
public int Id { get; set; }
//Role of user
public Role Role { get; set; }
// first name of user
public string Name { get; set; }
// Date of birth
public string DOB { get; set; }
public string Gender { get; set; }
public string Address { get; set; }
//Telephone number
public string MobileNumber { get; set; }
//email address
public string EmailAddress { get; set;}
// EF Relationship - a user can have many bookings
public IList<Booking> Bookings { get; set; } = new List<Booking>();
public Employee Employee { get; set; }
}

How to fully construct the newly added Entity

In my project i need to add Sales leads to the data context. The sales person user adds the leads and I need to send the email to manager for the Lead.
public partial class Lead
{
public Lead()
{
this.LeadActivities = new HashSet<LeadActivity>();
}
public long LeadID { get; set; }
public System.DateTime CreatedAt { get; set; }
public long CompanyID { get; set; }
public long ProductID { get; set; }
public long CreatedByUserID { get; set; }
public string Remarks { get; set; }
public LeadStatusEnum StatusID { get; set; }
public virtual Company Company { get; set; }
public virtual Product Product { get; set; }
public virtual User User { get; set; }
public virtual ICollection<LeadActivity> LeadActivities { get; set; }
}
[Serializable]
public partial class Person
{
public Person()
{
this.Contacts = new HashSet<Contact>();
this.Users = new HashSet<User>();
}
public long PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Designation { get; set; }
public Nullable<int> Gender { get; set; }
public Nullable<int> Title { get; set; }
public int StatusID { get; set; }
public string Thumbnail { get; set; }
public string Email { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
public virtual ICollection<User> Users { get; set; }
}
In the above entity, I have property UserID that is associated to Person table through CreatedByUserID. When I add the new lead, by following code, the User field remains null. Do I need to reconstruct it? if yes then how.
Edit1
Entity Creation is done by following code
Entity = new Model.Lead
{
CreatedAt = DateTime.Now,
CreatedByUserID = SessionManagement.GeneralSession.UserDetail.UserID
};
Entity.CreatedAt = Convert.ToDateTime(txtTimestamp.Value);
Entity.CompanyID = Convert.ToInt64(ddlCompany.SelectedValue);
Entity.CreatedByUserID = Convert.ToInt64(ddlUser.SelectedValue);
Entity.ProductID = Convert.ToInt64(lstProducts.SelectedValue);
Entity.Remarks = txtRemarks.Text;
DataSource.Leads.Add(Entity);
DataSource.SaveChanges();
Virtual lazy loading only works with proxy instances. Since you're explicitly constructing your Lead entity, lazy loading of the User navigation property after inserting the entity will not work.
Instead, you should use the DbSet.Create method to new up an instance of the derived proxy type. Then perform your insert, which will attach to the context, and lazy loading will subsequently work.
Alternatively, you can use your existing POCO, perform the insert and then fetch your inserted entity as its proxy from the DbSet by using the DbSet.Find method.
You should also check and make sure your foreign key id and navigation properties are correctly mapped, since properties CreatedByUserID and User would not be automatically associated by convention.

Relationship between tables

I use sqlmembership provider and that creates some tables. I need its user table.
My application has three types of users: teachers, students and other users. So I thought of three tables for them.
Each of them has a username which is registered by membership provider and saved in its own tables.
Now I don't know how to make the relationship between teachers or students tables to their usernames saved in the table of memberships, using entity framework.
I thought I can add a one to one relationship between users table created by membership provider and my tables after reverse engineering created tables by it to code first, but it seems is not allowed to change those tables.
Can someone show me how to make a relationship between teachers or students to their usernames (I mean their membership information)?
More Details: here are code first tables
public class aspnet_Users
{
public aspnet_Users()
{
this.aspnet_PersonalizationPerUser = new List<aspnet_PersonalizationPerUser>();
this.aspnet_Roles = new List<aspnet_Roles>();
}
public System.Guid ApplicationId { get; set; }
public System.Guid UserId { get; set; }
public string UserName { get; set; }
public string LoweredUserName { get; set; }
public string MobileAlias { get; set; }
public bool IsAnonymous { get; set; }
public System.DateTime LastActivityDate { get; set; }
public virtual aspnet_Applications aspnet_Applications { get; set; }
public virtual aspnet_Membership aspnet_Membership { get; set; }
public virtual ICollection<aspnet_PersonalizationPerUser> aspnet_PersonalizationPerUser { get; set; }
public virtual aspnet_Profile aspnet_Profile { get; set; }
public virtual ICollection<aspnet_Roles> aspnet_Roles { get; set; }
}
public class Techer
{
[Key]
public int TeacherId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string NationalNumber { get; set; }
public string PhoneNumber { get; set; }
public string Description { get; set; }
public int OfficeId { get; set; }
public virtual Office Office { get; set; }
}
public class Student
{
public int StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int OfficeId { get; set; }
public virtual Office Office { get; set; }
}
I've encountered a similar scenario, and what I ended up doing is creating a foreign key from my user profile table(s) to the membership table. So for example, the Teacher table would have a column called MembershipId, and it would foreign key to the Id column in the membership table. Then, in the Register action of my AccountController, I have something like this:
if (db.Memberships.Any(x => x.UserName == model.UserName)
{
// handle error here
// return view with error message "user name already in use"
}
var token = WebSecurity.CreateUserAndAccount(model.UserName, model.Password, null, true);
var membership = db.Memberships.SingleOrDefault(x => x.UserName == model.UserName);
if (membership != null)
{
var newProfile = new Teacher
{
Membership = membership
// add other properties here if required
}
db.Teachers.Add(newProfile);
db.SaveChanges();
}
*This code is untested, as I don't have VS available at the moment, but should be enough to get you on the right track.

Code First EF relationship duplicate

I have a working model, but have noticed that the relationship has been created twice in the database. Originally, it created two columns in the table, but with the addition of a specified foreign key attribute it has now just the one.
I have an Account class, which has many employers who can use the account. (one to many) Here are the classes:
public class Account
{
public int AccountId { get; set; }
[Required(ErrorMessage = Constants.ValidationMessages.FieldRequired)]
public string Name { get; set; }
public int? PrimaryUserId { get; set; }
[ForeignKey("PrimaryUserId")]
public Employer PrimaryUser { get; set; }
[ForeignKey("EmpAccountId")]
public ICollection<Employer> Employers { get; set; }
}
here is the inherited Employer class
public class Employer : User
{
public Employer()
{
DepartmentsToPost = new Collection<Department>();
Contacts = new Collection<Contact>();
}
[Display(Name = "Workplaces to advertise jobs")]
public virtual ICollection<Department> DepartmentsToPost { get; set; }
public int EmpAccountId { get; set; }
[ForeignKey("EmpAccountId")]
public virtual Account Account { get; set; }
public override string UserType
{
get { return "Employer"; }
}
}
User Table:
UserId
Username
FirstName
Surname
EmpAccountId
Discriminator
Account Table
AccountId
Name
PrimaryUserId
There is one link back to the User table - this is for the PrimaryUser field, and this is correct. There are two other relationships: Account -> Employers. EF has named them Account_Employers and Employer_Account. These are duplicates.
How can I prevent this occuring?
The Employers collection should be decorated with InversePropertyAttribute to point to the navigational property on the other side.
public class Account
{
public int AccountId { get; set; }
[Required(ErrorMessage = Constants.ValidationMessages.FieldRequired)]
public string Name { get; set; }
public int? PrimaryUserId { get; set; }
[ForeignKey("PrimaryUserId")]
public Employer PrimaryUser { get; set; }
[InverseProperty("Account")]
public ICollection<Employer> Employers { get; set; }
}

Categories