I have several cases where my navigation property is repeated in a class, or I don't want it to have the same name as the class it represents. Example:
public class Employee
{
public Guid EmployeeId { get; set; }
public string Name { get; set; }
}
public class Project
{
public Guid ProjectId { get; set; }
public DateTime Start { get; set; }
public Guid ResponsibleId { get; set; }
public virtual Employee Responsible { get; set; }
public Guid OwnerId { get; set; }
public virtual Employee Owner { get; set; }
}
When using EF Code First, it messes up the foreign keys, creates new ones with different names. How do I handle this?
Thanks a lot!
This should help:
public class Employee
{
public Guid EmployeeId { get; set; }
public string Name { get; set; }
public virtual ICollection<Project> ResponsibleProjects { get; set; }
public virtual ICollection<Project> OwnedProjects { get; set; }
}
public class Project
{
public Guid ProjectId { get; set; }
public DateTime Start { get; set; }
public Guid ResponsibleId { get; set; }
public virtual Employee Responsible { get; set; }
public Guid OwnerId { get; set; }
public virtual Employee Owner { get; set; }
}
public YourContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>()
.HasRequired(p => p.Owner)
.WithMany(e => e.OwnedProjects )
.HasForeignKey(p => p.OwnerId );
modelBuilder.Entity<Project>()
.HasRequired(p => p.Responsible)
.WithMany(e => e.ResponsibleProjects )
.HasForeignKey(p => p.ResponsibleId );
base.OnModelCreating(modelBuilder);
}
Note how relations are defined for both ends and how I point what exact field is used as a foreign key.
I ended up doing this, which works:
public class Employee
{
public Guid EmployeeId { get; set; }
public string Name { get; set; }
}
public class Project
{
public Guid ProjectId { get; set; }
public DateTime Start { get; set; }
public Guid ResponsibleId { get; set; }
[ForeignKey("ResponsibleId")]
public virtual Employee Responsible { get; set; }
public Guid OwnerId { get; set; }
[ForeignKey("OwnerId")]
public virtual Employee Owner { get; set; }
}
Thanks to Wiktor for the comment that lead to the solution.
Related
I work on an API and when I want to get data from a many-to-many relationship, I get back null.
The connection with the database is OK, and Post date work.
But when I get info from the database, the table for the many-to-many relationship is empty
public class User
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(30)]
public string Pseudo { get; set; }
[EmailAddress]
public string Mail { get; set; }
[Required]
public string Pwd { get; set; }
[Required]
public bool IsAdmin { get; set; }
public ICollection<Project> UsersProjectstry { get; set; }
public ICollection<UserProjectMTM> UsersProjects { get; set; }
}
public class Project
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(30)]
public string Name { get; set; }
[Required]
[MinLength(100)]
public string Description { get; set; }
public string? img { get; set; }
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; }
[Required]
public int SumGoal { get; set; }
public int Sum { get; set; }
[Required]
public User ProjectManager { get; set; }
public ICollection<UserProjectMTM> Donator { get; set; }
}
public class UserProjectMTM
{
public int PId { get; set; }
public Project Project { get; set; }
public int UId { get; set; }
public User User { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new ProjectConfig());
modelBuilder.ApplyConfiguration(new UserConfig());
modelBuilder.ApplyConfiguration(new CommentConfig());
modelBuilder.Entity<UserProjectMTM>().HasKey(x => new { x.UId, x.PId });
modelBuilder.Entity<UserProjectMTM>().HasOne(p=> p.Project).WithMany(u=> u.Donator).HasForeignKey(x=>x.PId);
modelBuilder.Entity<UserProjectMTM>().HasOne(u => u.User).WithMany(p=> p.UsersProjects).HasForeignKey(x => x.UId);
}
public IEnumerable<TEntity> GetAll()
{
return _Context.Set<TEntity>();
}
public TEntity? GetById(params object[] Id)
{
return _Context.Set<TEntity>().Find(Id);
}
I try a lot of things - so far without success.
I'm junior and I can't find the solution - please help.
I am using .NET 3.1.21 and I'm getting the error:
'CollectionNavigationBuilder<ApplicationUser, ClassroomGroup>' does not contain a definition for 'WithMany' and no accessible extension method 'WithMany' accepting a first argument of type 'CollectionNavigationBuilder<ApplicationUser, ClassroomGroup>' could be found (are you missing a using directive or an assembly reference?)
The syntax seems to be okay from what I've seen so far.
ApplicationDbContext
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
foreach (var relationship in builder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
relationship.DeleteBehavior = DeleteBehavior.Restrict;
builder.Entity<ApplicationUser>().HasMany(x => x.TeacherGroups).WithOne(x => x.Teacher).OnDelete(DeleteBehavior.SetNull);
builder.Entity<ApplicationUser>().HasMany(x => x.StudentGroups).WithMany(x => x.Students); //this .WithMany gives me the error
builder.Entity<ApplicationUser>().HasMany(x => x.UserRoles).WithOne(x => x.User)
.HasForeignKey(x => x.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
}
ApplicationUser
public class ApplicationUser : IdentityUser
{
public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
public virtual ICollection<ClassroomGroup> TeacherGroups { get; set; }
public virtual ICollection<ClassroomGroup> StudentGroups { get; set; }
public virtual ICollection<Task> CreatedTasks { get; set; }
public virtual ICollection<SchoolClassStudentTerm> SchoolClassStudentTerms { get; set; }
public virtual ICollection<GroupAssignment> CreatedGroupAssignments { get; set; }
public bool Disabled { get; set; }
public String FullName { get; set; }
public DateTime? StartTime { get; set; }
}
ClassroomGroup
public class ClassroomGroup
{
public int SubjectId { get; set; }
public virtual Subject Subject { get; set; }
public virtual SchoolClass SchoolClass { get; set; }
public int SchoolClassId { get; set; }
public String TeacherId { get; set; }
public virtual ApplicationUser Teacher { get; set; }
public int Id { get; set; }
public String Title { get; set; }
public virtual ICollection<ApplicationUser> Students { get; set; }
public int TermId { get; set; }
public virtual Term Term { get; set; }
public virtual ICollection<GroupAssignment> GroupAssignments { get; set; }
}
All packages are up to date
I was making an API for saving a model where it has one to many relationship with another model. When I applying automapping in it. it is giving me following error:
CreateContestDto -> Contest
tritronAPI.DTOs.CreateContestDto -> tritronAPI.Model.Contest
Type Map configuration:
CreateContestDto -> Contest
tritronAPI.DTOs.CreateContestDto -> tritronAPI.Model.Contest
Destination Member:
Problems
---> AutoMapper.AutoMapperMappingException: Missing type map
configuration or unsupported mapping.
Mapping types:
ProblemDto -> Problem
tritronAPI.DTOs.ProblemDto -> tritronAPI.Model.Problem
at lambda_method(Closure , ProblemDto , Problem , ResolutionContext )
My models are: Contest and Problem a contest contain many problems:
public class Contest
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public ICollection<Problem> Problems { get; set; }
public ICollection<ContestProgrammingLanguage>
ContestProgrammingLanguages { get; set; }
}
public class Problem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string ProblemName { get; set; }
[ForeignKey("User")]
public string ProblemAuthorId { get; set; }
public virtual User ProblemAuthor { get; set; }
public string AuthorName { get; set; }
//public virtual List<Resources> Resourceses { get; set; }
public string ProblemDescription { get; set; }
public bool IsPublished { get; set; }
public virtual ICollection<Submission> Submissions { get; set; }
public string Tags { get; set; }
//public Guid Contest_Id { get; set; }
public virtual Contest Contest { get; set; }
[ForeignKey("Contest")]
public int? Contest_Id { get; set; }
public short Score { get; set; }
//Timelimit in miliseconds
public int TimeLimit { get; set; }
//MemoryLimit in bytes
public int MemoryLimit { get; set; }
//More than source code limit is not allowed
public int? SourceCodeLimit { get; set; }
public virtual ICollection<TestFile> TestFiles { get; set; } = new
List<TestFile>();
}
public class CreateContestDto
{
public CreateContestDto()
{
this.Problems = new HashSet<ProblemDto>();
}
public string Name { get; set; }
public DateTime StartDate { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndDate { get; set; }
public DateTime EndTime { get; set; }
public string BackgroundImage { get; set; }
public string Description { get; set; }
public ICollection<ProblemDto> Problems { get; set; }
}
public class ProblemDto
{
public int Id { get; set; }
public string ProblemName { get; set; }
}
mapping profile:
CreateMap<CreateContestDto, Contest>().ForMember(
dest => dest.Problems , opt => opt.MapFrom(src =>
src.Problems));
controller code:
public async Task<IActionResult> AddContest([FromBody]
CreateContestDto contest)
{
var con = _mapper.Map<Contest>(contest);
this._uow.ContestRepository.Add(con);
return Ok();
}
I have already tried with reversemap selecting new id in mapping profile
You also need to add mappings for ProblemDTO to Problem:
CreateMap<CreateContestDto, Contest>();
CreateMap<ProblemDto, Problem>();
I am working on modeling a Contact Info Structure and haven't quite figured out how the relationships should be coded with EF Core. I am fairly new to using EF for data access layer.
I want to have a contact model which can contain Website, Phonenumbers, Emails, or Social Info. Then the contact info will be added to several different models. Any suggestions would be helpful, I am not sure how code this One to many with many table relationship or if it is even possible using EF.
Models so far
public class Contact
{
public String Id { get; set; }
public Int32 ContactType { get; set; } //Enum for Website, Phonenumbers, Emails, or Social
public String RecId { get; set; } //FK to multiple Models
public String RecType { get; set; }//Value for which model the RecID is for
public String Name { get; set; }
public String Value { get; set; }
}
public class ContactInfo
{
public virtual IList<Contact> Website { get; set; }
public virtual IList<Contact> PhoneNumbers { get; set; }
public virtual IList<Contact> Emails { get; set; }
public virtual IList<Contact> Socials { get; set; }
}
//Example of models to use the contact model
public class Company
{
....
pubic ContactInfo ContactInfo { get; set;}
}
public class Client
{
....
pubic ContactInfo ContactInfo { get; set;}
}
If I understand your question correctly, then you could use following code sample, but it is not exactly what you are trying to achieve. This may give you some understanding what you need to do with EF.
public class Contact
{
public String Id { get; set; }
public ContactType ContactType { get; set; } //Enum for Website, Phonenumbers, Emails, or Social
public String RecId { get; set; } //FK to multiple Models (This can't be the FK to multiple table as it should be FK for one table so that FK for Company would be CompanyId, FK for the Client should ClientId)
public String RecType { get; set; }//Value for which model the RecID is for (This need to rethink as it may not needed.)
public String Name { get; set; }
public String Value { get; set; }
// One to Many Relationship
public string CompanyId? { get; set; }
public string ClientId? { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class Company
{
public String Id { get; set; }
// Other properties
// One to Many Relationship
public ICollection<Contact> Contacts { get; set; }
}
public class Client
{
public String Id { get; set; }
// Other properties
// One to Many Relationship
public ICollection<Contact> Contacts { get; set; }
}
/* Db context */
public class YourDbContext : DbContext
{
public YourDbContext(DbContextOptions<YourDbContext> options)
: base(options)
{
}
public virtual DbSet<Contact> Contacts { get; set; }
public virtual DbSet<Company> Companies { get; set; }
public virtual DbSet<Client> Clients { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Contact>().HasKey(t => t.Id);
modelBuilder.Entity<Company>().HasKey(t => t.Id);
modelBuilder.Entity<Company>().HasMany(c => c.Contacts).WithOne(c => c.Company).HasForeignKey(k => k.CompanyId);
modelBuilder.Entity<Client>().HasKey(t => t.Id);
modelBuilder.Entity<Client>().HasMany(t => t.Contacts).WithOne(c =>c.Client).HasForeignKey(k => k.ClientId);
}
}
/* Db context - Endd */
public enum ContactType
{
Website,
PhoneNumbers,
Emails,
Social
}
Let me know if you need anymore information.
With the help from DSR, this is the solution I have (untested).
public class Company
{
public String Id { get; set; }
public String Name { get; set; }
public ICollection<ContactPhone> PhoneNumbers { get; set; }
public ICollection<ContactEmail> ContactEmail { get; set; }
public ICollection<ContactWebsite> ContactWebsite { get; set; }
public ICollection<ContactSocial> ContactSocial { get; set; }
}
public class Client
{
public String Id { get; set; }
public String Name { get; set; }
public ICollection<ContactPhone> PhoneNumbers { get; set; }
public ICollection<ContactEmail> ContactEmail { get; set; }
public ICollection<ContactWebsite> ContactWebsite { get; set; }
public ICollection<ContactSocial> ContactSocial { get; set; }
}
public class ContactWebsite
{
public String Id { get; set; }
public String Url { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class ContactPhone
{
public String Id { get; set; }
public String Type { get; set; }
public String Number { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class ContactEmail
{
public String Id { get; set; }
public String Category { get; set; }
public String Email { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
public class ContactSocial
{
public String Id { get; set; }
public String Site { get; set; }
public String Handle { get; set; }
public Company Company { get; set; }
public Client Client { get; set; }
}
I'm still new in creating Models using Entity Framework and MVC 4 Razor. I'm having a problem on how can I save a history of a model. How can I create a model that have a history on specific tables or fields ? For ex: If I wish to create a history on the changes on the school. Its still not clear to me how will I I create the model that saves history. How will be the triggering do I have to execute the save function on different models with the same data ?
Thank you so much in advance.
If anyone could be a simple example of model and a model history and how it is functioning, I'll be very grateful. Like a Sales or sales history.
Here's my code
One To Many
public class Child
{
[Key]
public int ChildID { get; set; }
[Required,Display(Name="Project Code")]
public string ProjectCode { get; set; }
public string Status { get; set; }
[DataType(DataType.Date)]
public DateTime StatusDate { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
public string MiddleName { get; set; }
[DataType(DataType.Date)]
public DateTime Birthdate { get; set; }
public string Gender {get;set;}
public string Address { get; set; }
public string Section { get; set; }
public int SchoolLevelID { get; set; }
public int SchoolYearID { get; set; }
public int AreaID { get; set; }
public int SchoolID { get; set; }
public int GradeLevelID { get; set; }
//Foreign Key - One to Many
public virtual SchoolLevel SchoolLevel { get; set; }
public virtual SchoolYear SchoolYear { get; set; }
public virtual Area Area { get; set; }
public virtual School School { get; set; }
public virtual GradeLevel GradeLevel{get;set;}
//Child is foreign key at the table
public virtual ICollection<Guardian> Guardians { get; set; }
}
public class SchoolLevel
{
public int SchoolLevelID { get; set; }
public string SchoolLevelName { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class SchoolYear
{
public int SchoolYearID { get; set; }
public string SchoolYearName { get; set; }
public virtual ICollection<Child> Children{get;set;}
}
public class Area
{
public int AreaID{get;set;}
public string AreaName { get; set; }
public virtual ICollection<Child> Children{get;set;}
}
public class School
{
public int SchoolID { get; set; }
public string SchoolName{get;set;}
public virtual ICollection<Child> Children { get; set; }
}
public class GradeLevel
{
public int GradeLevelID{get;set;}
public string GradeLevelName { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class ChildDbContext : DbContext
{
public DbSet<Child> Children { get; set; }
public DbSet<SchoolLevel> SchoolLevels { get; set; }
public DbSet<SchoolYear> SchoolYears { get; set; }
public DbSet<Area> Areas { get; set; }
public DbSet<School> Schools { get; set; }
public DbSet<GradeLevel> GradeLevels { get; set; }
public DbSet<Guardian> Guardians { get; set; }
}
You can use this approach: Create a History model. That contains 1 changeness like o log.
public class History
{
public int HistoryId { get; set; }
public int ModelType { get; set; } //it is ModelTypeEnum value.
public int ModelId { get; set; }
public string PropertyName { get; set; }
public string Propertyvalue {get;set;}
public DateTime ChangeDate { get; set; }
public int ChangedUserId { get; set; }
}
And Enum:
public enum ModelTypeEnum
{
Child =1,
SchoolLevel = 2,
//etc..
};
For example, when you edit 1 Child entity, give changed properties name and value, it's id, type and others (ChangeDate, ChangedUserId) to History and save histories. If 3 properties will change you should save 3 history entities. Then, you can load (filter) histories by ModelId, by ChangedUserId etc.