Entity Framework - How to configure the User Roles Many to Many Relationship - entity-framework

Below is the definition of the User entity, there is a navigation property Roles
public class User
{
public User()
{
Roles = new List<Role>();
}
public string Id { get; set; }
public string Username { get; set; }
public virtual ICollection<Role> Roles { get; set; }
Below is definition of the Role entity
public class Role
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
What i want is to define the many to many relationship and generate a relationship table UserRole which use UserId as the left key and RoleId as the right key, so how to write the configuration code?

User:
public class User
{
public User()
{
Roles = new List<Role>();
}
public string Id { get; set; }
public string Username { get; set; }
public virtual ICollection<UserRole> Roles { get; set; }
}
Role:
public class Role
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
UserRole:
public class UserRole
{
public string Id { get; set; }
public string UserId { get; set; }
public string RoleId{ get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
Override the OnModelCreating method in your dbcontext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasMany(c => c.Roles )
.WithMany()
.Map(x =>
{
x.MapLeftKey("UserId");
x.MapRightKey("RoleId");
x.ToTable("UserRoles");
});
}

Related

Entity Framework Core - 3 tier relationship

I have to apply a set of relationships with a system that incorporates a messaging system.
I have the two of my domain object with one mapping object (for the many-to-many relationship):
public class User
{
public User()
{
UserMails = new List<UserMail>();
}
public int Id { get; set; }
public ICollection<UserMail> UserMails { get; set; }
}
public class Mail
{
public Mail()
{
UserMails = new List<UserMail>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public ICollection<UserMail> UserMails { get; set; }
}
public class UserMail
{
public int Id { get; set; }
public int FromUserId { get; set; }
public User FromUser { get; set; }
public int ToUserId { get; set; }
public User ToUser { get; set; }
public int MailId { get; set; }
public Mail Mail { get; set; }
}
How would I configure this relationship using Fluent API such that there's a many to many relationship between User and Mail and Mail can have 2 foreign keys back to the UserFrom and UserTo?
Any help on this would be greatly appreciated.
If you are trying to model the relationship between a mail and its sender/recipient, then you don't need a many-to-many relation, or 2 foreign keys in your joining entity. Instead, you need 2 one-to-many relations like below -
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Mail> ReceivedMails { get; set; }
public ICollection<Mail> SentMails { get; set; }
}
public class Mail
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public int SenderId { get; set; }
public User Sender { get; set; }
public int RecipientId { get; set; }
public User Recipient { get; set; }
}
and you can configure them as -
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Mail>()
.HasOne(p => p.Sender)
.WithMany(p => p.SentMails)
.HasForeignKey(p => p.SenderId)
.OnDelete(DeleteBehavior.NoAction);
builder.Entity<Mail>()
.HasOne(p => p.Recipient)
.WithMany(p => p.ReceivedMails)
.HasForeignKey(p => p.RecipientId)
.OnDelete(DeleteBehavior.NoAction);
}

Entity Framework Code First Membership Provider Relationship Issue

I'm trying to code first on asp.net membership provider. When code first creates the table, it generates all tables and appropriate relationship to the bridge table but it also create an additional relationship from the AspNet_User(one) to Aspnet_Role(many). Do you know why it doing this? There shouldn't be any relationship between user and role table.
public class Aspnet_Role
{
public Aspnet_Role()
{
Aspnet_Users = new HashSet<Aspnet_Users>();
}
[Key]
public Guid RoleId { get; set; }
public string RoleName { get; set; }
public string LoweredRoleName { get; set; }
public string Description { get; set; }
public virtual ICollection<Aspnet_Users> Aspnet_Users { get; set; }
}
public class Aspnet_Users
{
public Aspnet_Users()
{
Aspnet_Roles = new HashSet<Aspnet_Role>();
}
[Key]
public 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 DateTime LastActivityDate { get; set; }
public virtual Aspnet_Membership Aspnet_Membership { get; set; }
public virtual ICollection<Aspnet_Role> Aspnet_Roles { get; set; }
}
public class StagingContext : DbContext
{
public DbSet<Aspnet_Role> Aspnet_Roles { get; set; }
public DbSet<Aspnet_Users> Aspnet_Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Aspnet_Users>()
.HasMany(r => r.Aspnet_Roles)
.WithMany()
.Map(m => m.ToTable("aspnet_UsersInRoles")
.MapRightKey("RoleId")
.MapLeftKey("UserId"));
}
}
I added the navigation property on the WithMany extension.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Aspnet_Users>()
.HasMany(r => r.Aspnet_Roles)
.WithMany(u => u.Aspnet_Users)
.Map(m => m.ToTable("aspnet_UsersInRoles")
.MapRightKey("RoleId")
.MapLeftKey("UserId"));
}

How to properly map entities using Fluent API?

I have two entities, a User and a UserProfile. The PK of User is UserId, the PK of UserProfile is UserProfileId. Every time a new user is created in my app, I create a new UserProfile whose PK is the same as the PK in User. When I then try to go update properties on the UserProfile I end up getting multiplicity errors or schema invalid errors. Here are my two entities:
public class User
{
public Guid UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int? PhoneExtension { get; set; }
public string Comment { get; set; }
public Boolean IsApproved { get; set; }
public int PasswordFailuresSinceLastSuccess { get; set; }
public DateTime? LastPasswordFailureDate { get; set; }
public DateTime? LastActivityDate { get; set; }
public DateTime? LastLockoutDate { get; set; }
public DateTime? LastLoginDate { get; set; }
public string ConfirmationToken { get; set; }
public DateTime? CreateDate { get; set; }
public Boolean IsLockedOut { get; set; }
public DateTime? LastPasswordChangedDate { get; set; }
public string PasswordVerificationToken { get; set; }
public DateTime? PasswordVerificationTokenExpirationDate { get; set; }
public virtual ICollection<Role> Roles { get; set; }
public virtual UserProfile UserProfile { get; set; }
}
public class UserProfile
{
public Guid UserProfileId { get; set; }
public virtual User ProfileOwner { get; set; }
public Int64? HomePhone { get; set; }
public Int64? MobilePhone { get; set; }
public virtual User Manager { get; set; }
}
..and here are my only defined relationships using Fluent API.
modelBuilder.Entity<UserProfile>()
.HasKey(e => e.UserProfileId);
modelBuilder.Entity<UserProfile>()
.Property(e => e.UserProfileId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<UserProfile>()
.HasRequired(e => e.ProfileOwner)
.WithRequiredDependent(r => r.UserProfile);
Finally, my UserService creates a new user and at the same time creates a new UserProfile whose Guid UserProfileId is the same as the User's Guid UserId. Right after the user and profile are created, I try to update the manager in the UserProfile with my UserProfileService using this:
public void UpdateUserProfile(UserProfile updatedUserProfile)
{
UserProfile oldUserProfile = GetUserProfileByID(updatedUserProfile.UserProfileId);
oldUserProfile.Manager = updatedUserProfile.Manager;
oldUserProfile.HomePhone = updatedUserProfile.HomePhone;
oldUserProfile.MobilePhone = updatedUserProfile.MobilePhone;
this.SetEntityState(oldUserProfile, EntityState.Modified);
this.UnitOfWork.SaveChanges();
}
The this.SetEntityState line throws this error:
Multiplicity constraint violated. The role 'UserProfile_ProfileOwner_Source' of the relationship 'WhelenPortal.Data.Context.UserProfile_ProfileOwner' has multiplicity 1 or 0..1.
I've been trying to get this working for TWO DAYS now, PLEASE HELP!!! Thanks in advance.
As requested, here is some additional information. I'm using the repository pattern and unit of work here. My GetUserProfileById code is below. The service uses the repository so I show both.
public UserProfile GetUserProfileByID(Guid id)
{
if (id == null)
throw new BusinessServicesException(Resources.UnableToRetrieveUserProfileExceptionMessage, new ArgumentNullException("id"));
try
{
Model.UserProfile userProfile = _userProfileRepository.GetUserProfileByID(id);
if (userProfile != null)
return ToServicesUserProfile(userProfile);
return null;
}
catch (InvalidOperationException ex)
{
throw new BusinessServicesException(Resources.UnableToRetrieveUserProfileExceptionMessage, ex);
}
}
..and the repository:
public UserProfile GetUserProfileByID(Guid id)
{
return this.GetDbSet<UserProfile>().Find(id);
}
So after much playing around this is what ended up working for me, hopefully it can help someone else in some fashion. My User class stayed exactly the same but my UserProfile class changed to this:
public class UserProfile
{
public Guid UserProfileId { get; set; }
public virtual User ProfileOwner { get; set; }
public Guid? ManagerId { get; set; }
public virtual User Manager { get; set; }
public Int64? HomePhone { get; set; }
public Int64? MobilePhone { get; set; }
}
And here is the fluent mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.HasOptional(u => u.UserProfile)
.WithRequired(u => u.ProfileOwner);
modelBuilder.Entity<UserProfile>()
.HasOptional(u => u.Manager)
.WithMany()
.HasForeignKey(u => u.ManagerId);
}

Entity Framework User Roles Many to Many Relationship

Hi I'm trying to set up my entity framework for a many to many relationship between User and Role.
The picture below shows what's in the database:
The Model for User is:
public class User : IEntity
{
public virtual int UserId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string UserName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string FirstName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string LastName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(200)]
public virtual string EmailAddress { get; set; }
public int AreaId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
//Navigation properties
//public virtual Role Role { get; set; }
public virtual Area Area { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
Model for Role is:
public class Role : IEntity
{
public int RoleId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public string Name { get; set; }
[Column(TypeName = "varchar")]
[StringLength(1000)]
public string Description { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
//Navigation Properties
public ICollection<User> Users { get; set; }
}
UserRole is:
public class UserRole
{
public int UserId { get; set; }
public int RoleId { get; set; }
//Navigation properties
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
So I thought I had this set up fine but in my code I go something like:
var roles = from r in user.Roles
select r.Name;
and it shoots itself giving errors of:
Server Error in '/' Application.
Invalid object name 'dbo.RoleUser'.
so I added the following to the context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(i => i.Roles)
.WithMany(u => u.Users);
}
However now I'm getting errors of:
Server Error in '/' Application.
Invalid column name 'Role_RoleId'.
Invalid column name 'User_UserId'.
So surely I don't have something set up here correctly. Can andybody point me in the right direction?
You don't need to model the link table UserRole as a class since it has only the primary keys of the tables participate in the relationship. So remove the UserRole class.
If you are modeling an existing database, EF may infer the link table name to be RoleUser. To avoid this you can configure the link table as follows.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(i => i.Roles)
.WithMany(u => u.Users)
.Map(m =>
{
m.ToTable("UserRole");
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
});
}

Entity Framework 4.1 Code First Self-Referencing One-to-Many and Many-to-Many Associations

I have a User that can have collection of users he likes...
Another user can have collection of users he likes....
If User A likes User B and if User B likes User A, then they get to hang out. I need to send each other their contact info. How do we represent such a model in Entity Framework Code First?
public class User
{
public int UserId { get; set; }
public int? UserLikeId { get; set; }
public virtual UserLike UserLike { get; set; }
}
public class UserLike
{
public int UserLikeId { get; set; }
public int UserId { get; set; }
public virtual User User { get; set; }
public virtual ICollection<User> LikeUsers { get; set; }
}
Is this model correct? I can't get this to work.
I've tried another way but that doesn't work too...
I tried to add collection of user to user table.
For ex :
public virtual ICollection<User> userlike { get; set; }
public class User
{
public int UserId { get; set; }
public virtual ICollection<UserLike> UserLikes { get; set; }
}
public class UserLike
{
public int UserLikeId { get; set; }
public int UserId { get; set; }
public virtual User User { get; set; }
public int LikeUserId { get; set; }
public virtual User LikeUser { get; set; }
}
I get this error when I try to add user and who they like:
Conflicting changes to the role 'UserLike_LikeUser_Target' of the relationship 'UserLike_LikeUser' have been detected.
What's the best way to represent such a model?
You don't really need a separate entity to describe the relationship, the object model below will do the trick:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public int? ThisUserLikesId { get; set; }
public virtual User ThisUserLikes { get; set; }
public virtual ICollection<User> LikeThisUser { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(u => u.ThisUserLikes)
.WithMany(u => u.LikeThisUser)
.HasForeignKey(u => u.ThisUserLikesId);
}
}
Now let's say you have a UserId in your hand and want to find the other User who likes this user which this user also like him:
using (var context = new Context())
{
// For a given user id = 1
var friends = (from u in context.Users
where u.UserId == 1
from v in u.LikeThisUser
where v.UserId == u.ThisUserLikesId
select new
{
OurUser = u,
HerFriend = v
})
.SingleOrDefault();
ExchangeContactInfo(friends.OurUser, friends.HerFriend);
}
Update 1:
A self referencing many-to-many association will be mapped to database using a join table which require a different object model and fluent API altogether:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<User> ThisUserLikes { get; set; }
public virtual ICollection<User> UsersLikeThisUser { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(u => u.ThisUserLikes)
.WithMany(u => u.UsersLikeThisUser)
.Map(c =>
{
c.MapLeftKey("UserId");
c.MapRightKey("OtherUserId");
c.ToTable("UserLikes");
});
}
}
Update 2:
As I explained in this post, a many-to-many association cannot have a payload (e.g EventId), and if that’s the case then we have to break it down to two one-to-many associations to an intervening class and I can see you’ve correctly created this class (UserLike) to represent the extra information attached to your self-referencing many-to-many association but the associations from this intermediate class are not correct as we need to define exactly 2 many-to-one association from UserLike to User like I showed in the following object model:
public class User
{
public int UserId { get; set; }
public string Email { get; set; }
public virtual ICollection ThisUserLikes { get; set; }
public virtual ICollection UsersLikeThisUser { get; set; }
}
public class UserLike
{
public int UserLikeId { get; set; }
public int LikerId { get; set; }
public int LikeeId { get; set; }
public int EventId { get; set; }
public User Liker { get; set; }
public User Likee { get; set; }
public virtual Event Event { get; set; }
}
public class Event
{
public int EventId { get; set; }
public string Name { get; set; }
}
public class Context : DbContext
{
public DbSet Users { get; set; }
public DbSet Events { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasMany(u => u.ThisUserLikes)
.WithRequired(ul => ul.Liker)
.HasForeignKey(ul => ul.LikerId);
modelBuilder.Entity()
.HasMany(u => u.UsersLikeThisUser)
.WithRequired(ul => ul.Likee)
.HasForeignKey(ul => ul.LikeeId)
.WillCascadeOnDelete(false);
}
}
Now you can use the following LINQ query to retrieve all the users who like each other:
using (var context = new Context())
{
var friends = (from u1 in context.Users
from likers in u1.UsersLikeThisUser
from u2 in u1.ThisUserLikes
where u2.LikeeId == likers.LikerId
select new
{
OurUser = u1.UserId,
HerFriend = u2.LikeeId
})
.ToList();
}
Hope this helps.