Updating foreign key entities in Entity Framework 4.1 - c#

I'm currently building a REST service using WebApi and the backing store is using EF4.1. I've run into a snag whereby I cannot update the foreign key...
The 2 model classes look like:
public class User
{
[Key]
public int UserId { get; set; }
public string Name { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
//
// Membership
public Membership Membership { get; set; }
}
public class Membership: Base
{
[Key]
public int MembershipId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public virtual Collection<User> Users { get; set; }
}
My application populates both the User object and the Membership object and passes them both to the following Update method:
public User Update(User entity)
{
if(entity.Membership != null)
dbContext.Memberships.Attach(entity.Membership);
dbContext.Entry(entity).State = EntityState.Modified;
dbContext.SaveChanges();
}
I've confirmed that both objects are present at the point of updating, but the membership foreign key is never persisted to the database. I'm certain I'm doing something simple wrong. Any insight would be greatly appreciated.
Thanks.

Related

Entity Framework Code First One to Many relationship return data using web api

These are my model and I am using entity framework code first approach.
public class Respondent
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RespondentId { get; set; }
public User Requester { get; set; }
public User Provider { get; set; }
public string Role { get; set; }
[NotMapped]
public ICollection<User> Providers { get; set; }
}
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public int UPI { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public bool IsPublic { get; set; }
[NotMapped]
public string Profile_Pic { get; set; }
[NotMapped]
public string Role { get; set; }
[NotMapped]
public List<string> Roles { get; set; }
}
Now I want to get all respondents by using following web api method but i am not getting correct result set and it is showing null values for Provider and requester and only returning respondent id.
public IQueryable<Respondent> GetRespondents()
{
return db.Respondents;
}
You can use the Include() function to load related data through your model's navigation properties.
Something like this.
// GET: api/Respondents
public IQueryable<Respondent> GetRespondents()
{
return db.Respondents.
Include(user=>user.Requester)
.Include(pro=pro.Providers).ToList();
}
Note that if you are using EntityFramework Core, you need the following namespace
using Microsoft.EntityFrameworkCore;
Otherwise you need:
using System.Data.Entity;

Entity Framework One-To-Many issue

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.

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.

ef modelBuilder force foreignkey a or foreignkey b

OK.
Background.
I was initially trying to make EF models along the lines of:
public class Person
{
[Key]
public Guid ID { get; set; }
public string Name { get; set; }
public Guid PhoneID { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
public class Org
{
[Key]
public Guid ID { get; set; }
public string Name { get; set; }
public Guid PhoneID { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
public class Phone
{
[Key]
public Guid ID { get; set; }
public string Number { get; set; }
public Guid EntityID { get; set; }
[ForeignKey("EntityID")]
public virtual User User { get; set; }
[ForeignKey("EntityID")]
public virtual Org Org { get; set; }
}
But I now (mostly) realize that this causes an issue with Foreign Key relationship integrity in SQL Server. So to correct this, I altered the Phone class to:
public class Phone
{
[Key]
public Guid ID { get; set; }
public string Number { get; set; }
public Guid? PersonID { get; set; }
public Guid? OrgID { get; set; }
[ForeignKey("PersonID")]
public virtual User User { get; set; }
[ForeignKey("OrgID")]
public virtual Org Org { get; set; }
}
Question.
How can I enforce / map a rule using modelbuilder / Fluent API to ensure a Phone object has either a PersonID or an OrgID?
Edit:
I do realise that this is creating a data integrity rule that I would be unable to do if I was designing the database in SQL Server, but to me it seems that EF has the potential flexibility to take database design to the next level.
I see EF (Code-First especially) as Microsoft's next big leap in their software development strategy. IMHO this is as big a leap as the introduction of .Net (Now there is a statement that should generate some debate!), that being moving the database design away from the database itself & integrating it in with the managed code.

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