Entity Framework - 3 tables have relationships with each other - entity-framework

I have 3 tables as follows:
ApplicationUser:
public class ApplicationUser : IdentityUser
{
..some basic properties..
// navigation properties
public virtual ICollection<Post> Posts { get; set; }
public virtual ICollection<Album> Albums { get; set; }
}
Post:
public class Post
{
public long Id { get; set; }
public string Content { get; set; }
public int? AlbumId { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual Album Album { get; set; }
}
Album:
public class Album
{
public int Id { get; set; }
public string Name { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
and finally ApplicationDbContext:
modelBuilder.Entity<ApplicationUser>()
.HasMany(a=>a.Posts)
.WithRequired(a=>a.User)
.HasForeignKey(a=>a.UserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Post>()
.HasKey(p => p.Id);
modelBuilder.Entity<Album>()
.HasKey(a => a.Id);
modelBuilder.Entity<ApplicationUser>()
.HasMany(u=>u.Albums)
.WithOptional()
.HasForeignKey(a=>a.UserId)
.WillCascadeOnDelete();
modelBuilder.Entity<Album>()
.HasMany(a=>a.Posts)
.WithRequired()
.HasForeignKey(p=>p.AlbumId)
.WillCascadeOnDelete();
When I run the migration and update database, I get an error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint
"FK_dbo.Posts_dbo.Albums_AlbumId". The conflict occurred in database
"aspnet-Link-20161012104217", table "dbo.Albums", column 'Id'.
Could anyone tell my why they conflict? It seems pretty legit to me.

In your code you set AlbumId as nullable but in configuration defined WithRequeired():
public class Post
{
public long Id { get; set; }
public string Content { get; set; }
public int? AlbumId { get; set; } //<-- this one
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual Album Album { get; set; }
}
modelBuilder.Entity<Album>()
.HasMany(a=>a.Posts)
.WithRequired() //<-- this one
.HasForeignKey(p=>p.AlbumId)
.WillCascadeOnDelete();
If AlbumId is nullable you should change the configuration:
//Ef by default conventions set the AlbumId as foreign key
modelBuilder.Entity<Album>()
.HasMany(a=>a.Posts)
.WithOptional(a=>a.Album);
and if AlbumId isn't nullable change the property:
public class Post
{
public long Id { get; set; }
public string Content { get; set; }
public int AlbumId { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual Album Album { get; set; }
}
and use following configuration:
//Ef by default conventions set the AlbumId as foreign key
modelBuilder.Entity<Album>()
.HasMany(a=>a.Posts)
.WithRequired(a=>a.Album)
.WillCascadeOnDelete();

Related

One to Many relashionship with Entity Framework

in my project (Asp.net Core Web Api) I have the tables "Truck" and "UserAccount with a one to many relashionship.
[Table("UserAccount")]
public class UserAccount : BaseClass
{
// Foreign Keys
[ForeignKey(nameof(UserAccountType))]
public int UserAccountTypeId { get; set; }
[ForeignKey(nameof(Gender))]
public int GenderId { get; set; }
[ForeignKey(nameof(Truck))]
public int TruckId { get; set; }
// Properties
public string LastName { get; set; }
public string FirstName { get; set; }
public string UserName { get; set; }
[DataType(DataType.EmailAddress)]
public string Mail { get; set; }
public string Login { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
// Navigation Properties
[IgnoreDataMember]
public virtual Gender Gender { get; set; }
//public virtual Truck Truck { get; set; }
[IgnoreDataMember]
public virtual UserAccountType UserAccountType { get; set; }
public Truck Truck { get; set; }
}
[Table("Truck")]
public class Truck : BaseClass
{
// Foreign Keys
// Properties
[Column(Order = 3)]
public string Name { get; set; }
[DataType(DataType.EmailAddress)]
[Column(Order = 4)]
public string Mail { get; set; }
[Column(Order = 5)]
public string Phone { get; set; }
[Column(Order = 6)]
public string VATNumber { get; set; }
// Navigation Properties
public virtual ICollection<TruckFoodType> TruckFoodTypes { get; set; }
public virtual ICollection<TruckOption> TruckOptions { get; set; }
public ICollection<UserAccount> UserAccounts { get; set; }
}
In the method OnModelCreation into my ApplicationDbContex file I have this to create the one to many relashionship:
modelBuilder.Entity<UserAccount>()
.HasOne<Truck>(u => u.Truck)
.WithMany(t => t.UserAccounts)
.HasForeignKey(u => u.TruckId);
But when I try to populate the UserAccount table I have this error message :
"Merge instruction is in conflict with "FK_User_Account_TruckId". This conflict occurse in the database xxx table dbo.Truck column Id" (Sorry, Comes from a french translation)
I don't hunderstand why.
Can somebody help me?
Thanks
OK, stupid mistake. In some cases the TruckId field from the User Account table can be null. So I added a "?" to this fields like this : public int? TruckId { get; set; } Sorry for inconvenience

Why do my one to many relationships in subclasses get a cycle error?

I want to have a one-to-many relation between subclasses of one master class,
and in second step use of master class for relationships with other class
please see below models:
BasePost.cs
public abstract class BasePost
{
[Key]
public long Id { get; set; }
public ICollection<Comment> Comments { get; set; }
}
Question.cs:
public class Question: BasePost
{
[Required] public string Title { get; set; }
public string Body { get; set; }
public ICollection<Answer> Answers { get; set; }
}
Answer.cs
public class Answer: BasePost
{
public string Body { get; set; }
public int Vote { get; set; }
public Question Question { get; set; }
public long QuestionId { get; set; }
}
Comment.cs
public class Comment
{
[Key]
public long Id { get; set; }
public string Text { get; set; }
public BasePost BasePost { get; set; }
public long BasePostId { get; set; }
public DateTime CreateDate { get; set; }
}
and finally in ApplicationDbContext.cs :
builder.Entity<Answer>()
.HasOne(x => x.Question)
.WithMany(a => a.Answers)
.HasForeignKey(k => k.QuestionId)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<Comment>()
.HasOne(x => x.BasePost)
.WithMany(a => a.Comments)
.HasForeignKey(k => k.BasePostId)
.OnDelete(DeleteBehavior.ClientSetNull);
but after migration and update database I get below error:
Introducing FOREIGN KEY constraint 'FK_BasePosts_BasePosts_QuestionId' on table 'BasePosts' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

Entity Framework. Resolve Zero Or One to one use one navigation property

Sorry for my English. I have the following entity:
public class MediaAlbum
{
[Key]
public Guid AlbumId { get; set; }
public string Title { get; set; }
public virtual ICollection<MediaImage> Images { get; set; }
public Guid? CoverId { get; set; }
[ForeignKey("ImageId")]
public virtual MediaImage Cover { get; set; }
}
public class MediaImage
{
[Key]
public Guid ImageId { get; set; }
public string Image { get; set; }
public Guid AlbumId { get; set; }
[ForeignKey("AlbumId")]
public virtual MediaAlbum Album { get; set; }
}
I need map navigation property Cover to Entity 'MediaImage'.
I tried to solve through fluentApi, but it not worked:
modelBuilder.Entity<MediaAlbum>().HasOptional(x => x.Cover).WithOptionalPrincipal()
.Map(x => x.MapKey("ImageId"));
use this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MediaAlbum>().HasMany(x => x.Images)
.WithRequired(x => x.Album).HasForeignKey(x=>x.AlbumId);
modelBuilder.Entity<MediaAlbum>().HasOptional(x => x.Cover);
}
foreign key is CoverId not ImageId:
public class MediaAlbum
{
[Key]
public Guid AlbumId { get; set; }
public string Title { get; set; }
public virtual ICollection<MediaImage> Images { get; set; }
public Guid? CoverId { get; set; }
[ForeignKey("CoverId")]// change to this
public virtual MediaImage Cover { get; set; }
}
Try this:
modelBuilder.Entity<MediaAlbum>()
.HasOptional(x => x.Cover)
.WithRequired(x => x.Album)
.WillCascadeOnDelete();

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");
});
}