Entity Framework Code First Fluent API One to Many - entity-framework

I have a ProductRequests table. It has a one to one relationship to ProductRequestDepartments. Which works correctly. I want to link ProductRequestDetails (which will have the actual Products (1 or more) of the ProductRequests.
public partial class WP__ProductRequests
{
[Key]
public int RequestId { get; set; }
[Required]
[StringLength(30)]
public string FromLocation { get; set; }
[Required]
public int ToDepartmentId { get; set; }
[StringLength(4000)]
public string Reason { get; set; }
[Required]
[StringLength(50)]
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
[StringLength(50)]
public string CompletedBy { get; set; }
public DateTime? CompletedDate { get; set; }
[Required]
[StringLength(1)]
public string Status { get; set; }
public ICollection<WP__ProductRequestDetails> ProductRequestDetails { get; set; }
public ICollection<WP__ProductRequestDepartments> ProductRequestDepartments { get; set; }
}
public partial class WP__ProductRequestDetails
{
[Key]
public int RequestDetailsId { get; set; }
[Required]
public int RequestId { get; set; }
[StringLength(20)]
public string ItemCode { get; set; }
[StringLength(100)]
public string ItemName { get; set; }
public int? Quantity { get; set; }
[Required]
[StringLength(1)]
public string Approved { get; set; }
public WP__ProductRequests ProductRequest { get; set; }
}
public partial class WP_ProductRequestDepartments
{
[Key]
public int ID { get; set; }
[StringLength(100)]
public string Department { get; set; }
public int? ApprovalManager { get; set; }
[StringLength(60)]
public string Reason { get; set; }
[StringLength(25)]
public string GeneralLedger { get; set; }
}
How do I wire this up in the Fluent API. So far I tried
public virtual DbSet<WP__ProductRequestDepartments> WP__ProductRequestDepartments { get; set; }
public virtual DbSet<WP__ProductRequestDetails> WP__ProductRequestDetails { get; set; }
public virtual DbSet<WP__ProductRequests> WP__ProductRequests { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<WP__ProductRequestDetails>()
.Property(e => e.Approved)
.IsFixedLength()
.IsUnicode(false);
modelBuilder.Entity<WP__ProductRequests>()
.Property(e => e.Status)
.IsFixedLength()
.IsUnicode(false);
modelBuilder.Entity<WP__ProductRequests>()
.HasRequired(a => a.ProductRequestDepartments)
.WithMany()
.HasForeignKey(a => a.ToDepartmentId);
//??
modelBuilder.Entity<WP__ProductRequests>()
.HasRequired(a => a.ProductRequestDetails)
.WithMany()
.HasForeignKey(a => a.RequestId);
}
ProductRequests -> ProductRequestDepartments works correctly (1 : 1)
ProductRequests -> ProductRequestDetail does NOT work (1 : N)
I'm getting
One or more validation errors were detected during model generation:"
WP__ProductRequests_ProductRequestDetails_Source: : Multiplicity is not valid in Role 'WP__ProductRequests_ProductRequestDetails_Source' in relationship 'WP__ProductRequests_ProductRequestDetails'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.

I believe you are looking for
modelBuilder.Entity<WP__ProductRequestDetails>()
.HasRequired(productRequestDetails => productRequestDetails.ProductRequest)
.WithMany(productRequest => productRequest.ProductRequestDetails)
.HasForeignKey(productRequestDetails => productRequestDetails.RequestId);

Related

Migration failed while trying to create a many to many relationship

I am trying to connect two tables with a code first migration. I thought EF would create many to many relationship table itself but I get error "build failed". While building whole project everything works fine. It's just the migration.
Following are my models -
Task:
[Key]
public int Id { get; set; }
public DateTime? CreatedAt { get; set; }
public DateTime? EndedAt { get; set; }
[Column(TypeName = "text")]
public string CreatedBy { get; set; }
[Required]
[Column(TypeName = "text")]
public string Title { get; set; }
[Required]
[Column(TypeName = "text")]
public string Description { get; set; }
public virtual TaskGroups TaskGroup { get; set; }
public string Status { get; set; }
[Column(TypeName = "text")]
public string WantedUser { get; set; }
TaskGroup:
[Required]
public int Id { get; set; }
[Required]
public string GroupName { get; set; }
public virtual Tasks Tasks { get; set; }
At first I've tried with ICollection<> but I got the same error.
My project is .Net Core 3.
Any ideas?
Edit
Tasks
[Key]
public int Id { get; set; }
public DateTime? CreatedAt { get; set; }
public DateTime? EndedAt { get; set; }
[Column(TypeName = "text")]
public string CreatedBy { get; set; }
[Required]
[Column(TypeName = "text")]
public string Title { get; set; }
[Required]
[Column(TypeName = "text")]
public string Description { get; set; }
public string Status { get; set; }
[Column(TypeName = "text")]
public string WantedUser { get; set; }
public IList<TaskGroupTask> TaskGroupTask { get; set; }
TaskGroups
[Key]
public int Id { get; set; }
[Required]
public string GroupName { get; set; }
public IList<TaskGroupTask> { get; set; }
TaskGroupTask
public int TaskId { get; set; }
public int TaskGroupId { get; set; }
public Tasks Tasks { get; set; }
public TaskGroups TaskGroups { get; set; }
DbContext
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<TaskGroupTask>(e =>
{
e.HasKey(p => new { p.TaskId, p.TaskGroupId });
e.HasOne(p => p.Tasks).WithMany(t =>
t.TaskGroupTask).HasForeignKey(p => p.TaskId);
e.HasOne(p => p.TaskGroups).WithMany(tg =>
tg.TaskGroupTask).HasForeignKey(p => p.TaskGroupId);
});
}
public DbSet<TaskGroupTask> TaskGroupTask { get; set; }
You will need to create a joining entity, like MyJoiningEntity or TaskGroupTask, whose sole purpose is to create a link between Task and TaskGroup. Following models should give you the idea -
public class Task
{
public int Id { get; set; }
public string Description { get; set; }
public IList<JoiningEntity> JoiningEntities { get; set; }
}
public class TaskGroup
{
public int Id { get; set; }
public string GroupName { get; set; }
public IList<JoiningEntity> JoiningEntities { get; set; }
}
// this is the Joining Entity that you need to create
public class JoiningEntity
{
public int TaskId { get; set; }
public int TaskGroupId { get; set; }
public Task Task { get; set; }
public TaskGroup TaskGroup { get; set; }
}
Then you can configure the relation in the OnModelCreating method of your DbContext class, like -
modelBuilder.Entity<JoiningEntity>(e =>
{
e.HasKey(p => new { p.TaskId, p.TaskGroupId });
e.HasOne(p => p.Task).WithMany(t => t.JoiningEntities).HasForeignKey(p => p.TaskId);
e.HasOne(p => p.TaskGroup).WithMany(tg => tg.JoiningEntities).HasForeignKey(p => p.TaskGroupId);
});
This will define a composite primary key on JoiningEntity table based on the TaskId and TaskGroupId properties. Since this table's sole purpose is to link two other tables, it doesn't actually need it's very own Id field for primary key.
Note: This approach is for EF versions less than 5.0. From EF 5.0 you can create a many-to-many relationship in a more transparent way.
Since I have some time, I've decided to pull all pices of the code in one place. I think it would be very usefull sample how to create code-first many-to-many relations for database tables. This code was tested in Visual Studio and a new database was created without any warnings:
public class Task
{
public Task()
{
TaskTaskGroups = new HashSet<TaskTaskGroup>();
}
[Key]
public int Id { get; set; }
public DateTime? CreatedAt { get; set; }
public DateTime? EndedAt { get; set; }
[Column(TypeName = "text")]
public string CreatedBy { get; set; }
[Required]
[Column(TypeName = "text")]
public string Title { get; set; }
[Required]
[Column(TypeName = "text")]
public string Description { get; set; }
public string Status { get; set; }
[Column(TypeName = "text")]
public string WantedUser { get; set; }
[InverseProperty(nameof(TaskTaskGroup.Task))]
public virtual ICollection<TaskTaskGroup> TaskTaskGroups { get; set; }
}
public class TaskGroup
{
public TaskGroup()
{
TaskTaskGroups = new HashSet<TaskTaskGroup>();
}
[Required]
public int Id { get; set; }
[Required]
public string GroupName { get; set; }
[InverseProperty(nameof(TaskTaskGroup.TaskGroup))]
public virtual ICollection<TaskTaskGroup> TaskTaskGroups { get; set; }
}
public class TaskTaskGroup
{
[Key]
public int Id { get; set; }
public int TaskId { get; set; }
[ForeignKey(nameof(TaskId))]
[InverseProperty(nameof(TaskTaskGroup.Task.TaskTaskGroups))]
public virtual Task Task { get; set; }
public int TaskGroupId { get; set; }
[ForeignKey(nameof(TaskGroupId))]
[InverseProperty(nameof(TaskTaskGroup.Task.TaskTaskGroups))]
public virtual TaskGroup TaskGroup { get; set; }
}
public class TaskDbContext : DbContext
{
public TaskDbContext()
{
}
public TaskDbContext(DbContextOptions<TaskDbContext> options)
: base(options)
{
}
public DbSet<Task> Tasks { get; set; }
public DbSet<TaskGroup> TaskGroups { get; set; }
public DbSet<TaskTaskGroup> TaskTaskGroups { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=localhost;Database=Task;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TaskTaskGroup>(entity =>
{
entity.HasOne(d => d.Task)
.WithMany(p => p.TaskTaskGroups)
.HasForeignKey(d => d.TaskId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_TaskTaskGroup_Task");
entity.HasOne(d => d.TaskGroup)
.WithMany(p => p.TaskTaskGroups)
.HasForeignKey(d => d.TaskGroupId)
.HasConstraintName("FK_TaskTaskGroup_TaskCroup");
});
}
}

Defining the one to many relationship in OnModelCreating using Entity Framework Core 3.1

I am new to Entity Framework Core 3.1 and trying to define the one-to-many relationship between two tables. I am currently struggling and getting compilation errors. Could somebody tell me what the problem could be.
The error is:
PersonNote does not contain the definition for PersonNote
I am currently getting is at line
entity.HasOne(d => d.PersonNote)
How else could I define one-to-many relationship?
The two tables are Person and PersonNote. One Person can have many PersonNotes. I have defined the models for them
public class Person
{
public int Id { get; set; }
public int? TitleId { get; set; }
public string FirstName { get; set; }
public string FirstNamePref { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime? DateOfBirth { get; set; }
public string Gender { get; set; }
public int AddressId { get; set; }
public string TelephoneNumber { get; set; }
public string MobileNumber { get; set; }
public string Email { get; set; }
public int? PartnerId { get; set; }
public bool Enabled { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
public string ModifiedBy { get; set; }
public DateTime Modified { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
public Address Address { get; set; }
public Title Title { get; set; }
public Client Client { get; set; }
internal static IEnumerable<object> Include(Func<object, object> p)
{
throw new NotImplementedException();
}
public PersonNote PersonNote { get; set; }
}
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
public IEnumerable<PersonNote> GetPersonNotes(int personId)
{
var PersonNotes = PersonNote
.Include(x => x.)
.Where(x => x.Id == personId)
.ToList();
return PersonNotes;
}
I have tried the following in OnModelCreating:
modelBuilder.Entity<PersonNote>(entity =>
{
entity.ToTable("PersonNote", "common");
entity.HasOne(d => d.PersonNote)
.WithMany(p => p.Person)
.HasForeignKey(d => d.PersonId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_commonPersonNote_commonPerson");
});
You should have have something like this (other properties are omitted):
class Person
{
[Key]
public int Id { get; set; }
public List<PersonNote> PersonNotes { get; set; }
}
class PersonNote
{
[Key]
public int Id { get; set; }
public int PersonId { get; set; }
}
class StackOverflow : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<PersonNote> PersonNotes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasMany(p => p.PersonNotes)
.WithOne()
.HasForeignKey(p => p.PersonId);
}
}

Entity Framework 1 to 1 / 1 to *

I have this setup of classes:
public class User
{
public int Id { get; set; }
public string LoginName { get; set; }
public int CurrentPasswordId { get; set; }
public virtual ArchivedPassword CurrentPassword {get;set;}
public virtual ICollection<ArchivedPassword> UsedPasswords { get; set; }
}
public class ArchivedPassword
{
public int Id { get; set; }
public string Hash { get; set; }
public int UserId { get; set; }
public virtual User User { get; set; }
public virtual ICollection<User> Users { get; set; }
}
ModelBuilder.Entity<ArchivedPassword>()
.HasMany(e => e.Users)
.WithRequired(e => e.CurrentPassword)
.HasForeignKey(e => e.CurrentPasswordId)
.WillCascadeOnDelete(false);
ModelBuilder.Entity<User>()
.HasMany(e => e.UsedPasswords)
.WithRequired(e => e.User)
.HasForeignKey(e => e.UserId)
.WillCascadeOnDelete(false);
When i try to add a user and a password, ef canĀ“t figure out the update order.
Is this a mapping Problem?
I am not expert on Database .But i think you can not make two different Foreign Keys for same tables.But you can success what you want as below code
public class UserContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Password> Paswords { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
[NotMapped]
public Password Password
{
get
{
return Passwords.ElementAt(Passwords.Count - 1);
}
}
public virtual ICollection<Password> Passwords { get; set; }
}
public class Password
{
public int Id { get; set; }
public string Hash { get; set; }
public virtual User User { get; set; }
}

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();

Sequence contains more than one matching element codefirst

I'm getting this error when trying to update relationship (one to one)
with fluent api this are my classes :
public class Organisation
{
[Key]
public int OrganisationId { get; set; }
public string organisationName { get; set; }
public string FirstName { get; internal set; }
public string LastName { get; internal set; }
public virtual ApplicationUser User { get; set; }
[Required]
public string ApplicationUserId { get; set; }
public int? OrganisationDetalisId { get; set; }
public virtual OrganisationDetalis OrDetalis { get; set; }
public virtual ICollection<Aeroa> aeroa { get; set; }
public virtual ICollection<Order> orders { get; set; }
}
public class OrganisationDetalis
{
[Key]
public int OrganisationDetalisId { get; set; }
//remove for clear code
public int OrganisationId { get; set; }
public virtual Organisation organisation { get; set; }
}
public DbSet<Organisation> organisation { get; set; }
public DbSet<OrganisationDetalis> OrDetalis { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<OrganisationDetalis>()
.HasKey(o => o.OrganisationId);
modelBuilder.Entity<Organisation>()
.HasOptional(ad => ad.OrDetalis).WithRequired(oo => oo.organisation);
}
but I keep getting that error when updating view nugget console
where is the problem?