Entity Framwork Mapping One-To-One Aspnet_Membership Table - c#

I am using EF5 with the default aspnet_Membership Schema.
I have a custom User object with a foreign key referencing the aspnet_Membership table.
The foreign key in the User object is called 'AspnetID'
I need to map this one-to-one relationship with the fluent API but I am having no luck
Objects look like this:
public class aspnet_Membership
{
[Key]
public Guid UserId { get; set; }
public string Email { get; set; }
public DateTime CreateDate { get; set; }
public aspnet_Users aspnet_User { get; set; }
public User User { get; set; }
}
public class User
{
public int UserID { get; set; }
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
public Guid AspnetID { get; set; } //This is the foreign key referencing aspnet_Membership
public virtual aspnet_Membership Aspnet_Membership { get; set; }
}
I have tried this:
modelBuilder.Entity<User>().HasRequired(u => u.Aspnet_Membership).WithOptional(u => u.User);
But I know that I need to map the foreign key name some how...Any ideas?

You need to use WithRequiredPricipal() instead of WithOptional()
modelBuilder.Entity<User>()
.HasRequired(t => t.Aspnet_Membership)
.WithRequiredPrincipal(t => t.User);

Related

Mapping EF Foreign key with different names

I have the below domain classes:
public class Product
{
public Guid? Id { get; set; }
public string? Name { get; set; }
}
public class Order
{
public Guid? Id { get; set; }
public string? Address{ get; set; }
public Guid? ProductId{ get; set; }
}
I am not using navigation properties for setting the foreign key but am doing it as below:
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.HasOne<Product>()
.WithMany()
.HasForeignKey(c => c.ProductId);
}
My problem when I do the update-database, it says that the field ProductId does not exist. This is because it named as Id in table product but in table order it is named as ProductId. Is there a way to map the foreign key with a different name?
Modify the Product class
public class Product
{
public Guid? Id { get; set; }
public string? Name { get; set; }
public ICollection<Order> Orders {get; set;}
}
The relationship will work properly.
Reference: Relationships

Entity Framework - Foreign keys and Navigation Properties

I need your help understanding relationships between tables. I´m having a hard time trying to understand the usage/need of using navigation properties with foreign key properties to define relantionships.
Given the 2 classes below,
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public string Name{ get; set; }
}
public class Package
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid AccountId { get; set; }
public virtual Person Account { get; set; }
public Guid ShipperId { get; set; }
public virtual Client Shipper { get; set; }
[Required]
public Guid ReceiverId { get; set; }
public virtual Client Receiver { get; set; }
}
If I try to update the database, I get the error
Introducing FOREIGN KEY constraint 'FK_' on table 'Packages' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
On the other hand if I remove the property public Guid ....Id { get; set; }, the database is created with the foreign keys but the [Required] annotation as no effect.
What´s the difference between including a Guid property and not?
try to use this classes:
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public string Name{ get; set; }
[InverseProperty(nameof(Package.Account))]
public virtual ICollection<Package> Packages { get; set; }
}
public class Package
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid AccountId { get; set; }
[ForeignKey(nameof(AccountId))]
[InverseProperty("Packages")]
public virtual Person Account { get; set; }
}
and use this code in dbcontext:
modelBuilder.Entity<Package>(entity =>
{
entity.HasOne(d => d.Person)
.WithMany(p => p.Packages)
.HasForeignKey(d => d.AccountId)
.OnDelete(DeleteBehavior.ClientSetNull);
});

Fluent API one to one relationship mapping

I am trying to make a "One to one" association using the Fluent API. Here are my classes :
public class Person
{
public Guid Id { get; set; }
public Guid ProfilId { get; set; }
public DateTime InsertDate { get; set; }
public DateTime UpdateDate { get; set; }
public virtual Profil Profil { get; set; }
}
public class Profil
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public String Email { get; set; }
public virtual Person Person { get; set; }
}
public class PersonMap : EntityTypeConfiguration<Person>
{
public PersonMap()
{
...
ToTable("Person");
HasRequired(t => t.Profil)
.WithOptional(c => c.Person)
.Map(m => m.MapKey("ProfilId"));
}
}
This implementation throws an exception Invalid column name 'ProfilId'.
Would somebody tell me how to set up a mapping with 1-1 relationship using these classes?
Thank you
When configuring one-to-one relationships,Entity Framework requires that the primary key of the dependent also be the foreign key, so you can map the relationship using Data Annotations as follow:
public class Person
{
[Key]
[ForeignKey("Profil")]
public Guid ProfilId { get; set; }
public DateTime InsertDate { get; set; }
public DateTime UpdateDate { get; set; }
public virtual Profil Profil { get; set; }
}
Or using Fluent Api:
HasKey(t=>t.ProfilId);
HasRequired(t => t.Profil).WithOptional(c => c.Person);
Edit 1:
Well, EF lets you create an one-to-one relationship between two entities with their own PKs, but you can't use a FK property, so, remove ProfileId in Person entity and configure the relationship this way:
HasRequired(t => t.Profil).WithOptional(c => c.Person);
The MapKey method is used to change the foreign key name in the database, but you can't have a property with the same name in your entity, otherwise, an exception will be thrown.

Can't add multiple Foreign Keys to a table - EF - Code First

I decided to play around with the code first option with the EF, however, i've run into a problem regarding multiple foreign keys in a single table.
The error I get is:
The referential relationship will result in a cyclical reference that is not allowed. [ Constraint name = FK_dbo.Comments_dbo.Users_UserId ]
I have three tables, User, Post and Comments. Using my limited knowledge in this field, I have created three classes.
User
public class User
{
[Key]
public int UserId { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public DateTime JoinDate { get; set; }
public string Password { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public User()
{
Posts = new List<Post>();
}
}
Post
public class Post
{
[Key]
public int PostId { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public DateTime PublishDate { get; set; }
public int UserId { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public Post()
{
Comments = new List<Comment>();
}
}
Comment
public class Comment
{
[Key]
public int CommentId { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public DateTime CommentDate { get; set; }
public int UserId { get; set; }
public int PostId { get; set; }
}
The relationship between the UserId in the 'User' table, and the UserId in the 'Post' table is fine. However, I run into problems when I wish to create a relationship from the 'Comment' table to the 'Post' and 'User' tables. I'm not sure what i'm doing wrong, as each table is connected to their respective Id. Any help would be appreciated.
You will probably have to disable cascading delete on one or two of the relationships, for example for the relationships of User.Posts and User.Comments. You must do it with Fluent API in an overridden OnModelCreating of your derived DbContext:
modelBuilder.Entity<User>()
.HasMany(u => u.Posts)
.WithRequired()
.HasForeignKey(p => p.UserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
.HasMany(u => u.Comments)
.WithRequired()
.HasForeignKey(c => c.UserId)
.WillCascadeOnDelete(false);
Alternatively you could make the relationships to User optional instead of required. It would be as simple as making the UserId foreign key properties in Post and Comment nullable:
public int? UserId { get; set; }
It might even make sense from a business perspective to allow keeping posts and comments in the system as anonymous even after the user has been deleted, represented by a null value of UserId in Post and Comment.
You need to configure your mappings: http://www.remondo.net/code-first-fluent-api-entity-type-configuration/

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.

Categories