Many to many mapping not creating correct tables - c#

I have a Template class
public class Template
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual Template RelatedTemplate { get; set; }
public virtual Field RelatedTemplatePrimaryField { get; set; }
public virtual ICollection<Field> Fields { get; set; }
}
And a Field class
public class Field
{
public int Id { get; set; }
public string Name { get; set; }
public int Min { get; set; }
public int Max { get; set; }
public bool AllowEmpty { get; set; }
public bool IsCollection { get; set; }
public virtual ICollection<Template> Templates { get; set; }
}
The problem is it's not creating a many to many relationship, it just adds a FK on the fields table, I want a many to many relationship on
Fields ICollection<Field> Fields
and
ICollection<Template> Templates
EDIT:
If I remove
public virtual Template RelatedTemplate { get; set; }
public virtual Field RelatedTemplatePrimaryField { get; set; }
It works... Any ideas?

This is a case where you must help EF to correctly recognize your relations. You can do it either by data annotations:
[InverseProperty("Fields")]
public virtual ICollection<Template> Templates { get; set; }
or by fluent-API:
modelBuilder.Entity<Template>()
.HasMany(t => t.Fields)
.WithMany(f => f.Templates);

Related

I got a the entity type requires primary key error

When i try to connect with my database and my class i got this error
But this error appear just for my Consoles,KeyboardMouse and Headphones tables. But they have already primary keys.
and here is my context class
public class EcommContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=.;Database=eCommerce;Trusted_Connection=true");
}
public DbSet<Product> Products { get; set; }
public DbSet<Card> Cards { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Consoles> Consoles { get; set; }
public DbSet<Headphone> Headphones { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Mouse> Mouses { get; set; }
public DbSet<MousePad> MousePads { get; set; }
public DbSet<Keyboard> Keyboards { get; set; }
public DbSet<KeyboardAndMouse> KeyboardMouse { get; set; }
public DbSet<Gamepad> Gamepads { get; set; }
public DbSet<Computer> Computers { get; set; }
}
And my entity classes
public class Headphone:IEntity
{
public int HeadphonesId { get; set; }
public int ProductId { get; set; }
public bool IsWireless { get; set; }
public string Type { get; set; }
public string Color { get; set; }
public bool IsGaming { get; set; }
}
public class KeyboardAndMouse:IEntity
{
public int KmId { get; set; }
public int ProductId { get; set; }
public string Color { get; set; }
}
public class Consoles:IEntity
{
public int ConsoleId { get; set; }
public int ProductId { get; set; }
public string Color { get; set; }
public int GamepadNumber { get; set; }
public int Capacity { get; set; }
}
How can I solve that. Does anyone help me ?
In your entity class you need to use [Key] annotation for primary key field. Try like below.
public class Headphone:IEntity
{
[Key]
public int HeadphonesId { get; set; }
}
public class KeyboardAndMouse:IEntity
{
[Key]
public int KmId { get; set; }
}
public class Consoles:IEntity
{
[Key]
public int ConsoleId { get; set; }
}
Please check this out for more information : https://learn.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#configuring-a-primary-key
FYI - By convention, a property named Id or <type name>Id will be configured as the primary key of an entity.
So if you had HeadphoneId field in Headphone class then it will select that column as primary key by convention and no need to use [Key] annotation or Fluent API to define Primary key field.

Entity Framework - group multiple foreign keys into a single column

New to EF here and having some difficulty.
I have about 24 tables I need to create with code-first. Each one of these tables has around 2 - 10 many-to-one relationships that are simple and can be represented with 1 table. Here are just a few of my classes to illustrate my structure...
namespace EMRS
{
public class ERecord
{
[Key]
public int PCRId { get; set; }
public virtual List<EFirstClass> EFirstClass {get; set;}
public virtual List<ESecondClass> ESecondClass { get; set; }
}
public class EFirstElement
{
[Key]
public int ElementId { get; set; }
public ElementCode stuff1 { get; set; } //eAirway.06
public string stuff2 { get; set; }
public int PCRId { get; set; }
public virtual ERecord EReportId { get; set; }
public virtual List<SubElement> Stuff4List { get; set; }
public virtual List<SubElement> Stuff5List { get; set; }
public virtual List<SubElement> Stuff6List { get; set; }
public virtual List<SubElement> Stuff7List { get; set; }
}
public class ESecondElement
{
[Key]
public int ElementId { get; set; }
public ElementCode Stuff9 { get; set; }
public ElementCode Stuff10 { get; set; }
public int PCRId { get; set; }
public virtual ERecord EReportId { get; set; }
public virtual List<SubElement> StuffList11 { get; set; }
public virtual List<SubElement> StuffList12 { get; set; }
public virtual List<SubElement> StuffList13 { get; set; }
public virtual List<SubElement> StuffList14 { get; set; }
public virtual List<SubElement> StuffList15 { get; set; }
public virtual List<SubElement> StuffList16 { get; set; }
public virtual List<SubElement> StuffList17 { get; set; }
}
public class SubElement
{
public int SubElementId { get; set; }
public string Value { get; set; }
public dynamic Type { get; set; }
public int ElementId { get; set; }
}
}
If I were to create a class/table for each individual 1 to many relationship in the element classes, I would end up with many tables with exactly the same structure. What I would like to do would be to have a foreign key in the SubElement class that references more than 1 class.
I tried having a parentelement abstract class and inheriting it in all of my element classes but EF created a table for that class(Parentelement) and placed all columns in all Element classes within that table.
Is there any way to do this with EF Code first?

Linq Include not loading List

I've been for a while trying to find out why the Include clause is not loading the related collection: I have two classes with a one-to-many relationship:
public class AgencyNote : IAutId
{
[Key]
public int aut_id { get; set; }
public string Comment { get; set; }
[DisplayName("Note Created Date")]
public DateTime NoteDate { get; set; }
[DisplayName("Contact Date")]
public DateTime ContactDate { get; set; }
[ForeignKey("tbl_agency")]
public int AgencyId { get; set; }
[DisplayName("User")]
public string RipsUser { get; set; }
public virtual ICollection<AgencyNoteAttachment> AgencyNoteAttachments { get; set; }
public virtual tbl_agency tbl_agency { get; set; }
}
and
public class AgencyNoteAttachment
{
[Key]
public int aut_id { get; set; }
public string Url { get; set; }
public string FileName { get; set; }
public int AgencyNoteId { get; set; }
[NotMapped]
[ForeignKey("AgencyNoteId")]
public virtual AgencyNote AgencyNote { get; set; }
}
Context class:
public DbSet<AgencyNote> AgencyNotes { get; set; }
public DbSet<AgencyNoteAttachment> AgencyNoteAttachments { get; set; }
This is the action where I'm using the Include clause:
private IQueryable<AgencyNote> GetNotes(int agencyId)
{
return _ctx.AgencyNotes
.Include(a => a.tbl_agency)
.Include(a => a.AgencyNoteAttachments)
.OrderByDescending(f => f.NoteDate)
.Where(x => x.AgencyId == agencyId);
}
I'm getting AgencyNotesAttachments always null from this action even if I know it's not null, what's going on? Any question let me know...
If you add just the navigation properties between the related entities, then EF will create the FK column for you in the AgencyNoteAttachment table. Now, EF by convention can interpret AgencyNoteId is the FK of that relationship, but is good idea do that explicitly as you already have in your model or using ForeignKey attribute on FK property:
public class AgencyNoteAttachment
{
[Key]
public int aut_id { get; set; }
public string Url { get; set; }
public string FileName { get; set; }
[ForeignKey("AgencyNote")]
public int AgencyNoteId { get; set; }
public virtual AgencyNote AgencyNote { get; set; }
}
If you want to learn more about conventions, take a look this link

EF TPT generating duplicate foreign keys

I am writing an application which uses inheritance and I'm trying to map this to a SQL Server database with TPT structure.
However, for some reason EF generates duplicate foreign keys in both the superclass and subclass tables.
I have these classes:
public abstract class Answer
{
public int AnswerId { get; set; }
[Required]
[MaxLength(250, ErrorMessage = "The answer cannot contain more than 250 characters")]
public String Text { get; set; }
[Required]
[MaxLength(1500, ErrorMessage = "The description cannot contain more than 1500 characters")]
public String Description { get; set; }
public User User { get; set; }
}
public class AgendaAnswer : Answer
{
[Required]
public AgendaModule AgendaModule { get; set; }
}
public class SolutionAnswer : Answer
{
[Required]
public SolutionModule SolutionModule { get; set; }
}
public abstract class Module
{
// for some reason EF doesn't recognize this as primary key
public int ModuleId { get; set; }
[Required]
public String Question { get; set; }
public String Description { get; set; }
[Required]
public DateTime StartTime { get; set; }
[Required]
public DateTime EndTime { get; set; }
public virtual IList<Tag> Tags { get; set; }
}
public class AgendaModule : Module
{
public IList<AgendaAnswer> AgendaAnswers { get; set; }
}
public class SolutionModule : Module
{
public IList<SolutionAnswer> SolutionAnswers { get; set; }
}
public class User
{
public int UserId { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public int Zip { get; set; }
public bool Active { get; set; }
public virtual IList<AgendaAnswer> AgendaAnswers { get; set; }
public virtual IList<SolutionAnswer> SolutionAnswers { get; set; }
}
And this is the content of my DbContext class:
public DbSet<AgendaModule> AgendaModules { get; set; }
public DbSet<SolutionModule> SolutionModules { get; set; }
public DbSet<AgendaAnswer> AgendaAnswers { get; set; }
public DbSet<SolutionAnswer> SolutionAnswers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<Module>().HasKey(m => m.ModuleId);
modelBuilder.Entity<Answer>().HasKey(a => a.AnswerId);
modelBuilder.Entity<AgendaAnswer>().Map(m =>
{
m.ToTable("AgendaAnswers");
});
modelBuilder.Entity<SolutionAnswer>().Map(m =>
{
m.ToTable("SolutionAnswers");
});
}
When I run my application, EF creates the tables how I want them (TPT), but it duplicates the foreign key to users in each of them (see picture).
Thanks in advance
As noted in my comment above, the solution is to remove the AgendaAnswers and SolutionAnswers properties from the User class.
If you want to keep those collections in the User class, you might have to remove the User and UserId properties from the Answer class and instead duplicate them in the AgendaAnswer and SolutionAnswer classes. See this SO question for more information.

Entity Framework with ASP.NET MVC is saving value to wrong column

I have the following classes, a challenge has many submissions and it also has a winner.
The problem is that in my database Entity framework has created two columns on the Submissions table [ChallengeId] & [Challenge_ChallengeId] when I save an object it is added to the ChallengeId Column but relationship is being held on the Challenge_ChallengeId column.
Is there an issue with my models that is causing this or is some way I can set to hold the relationship and save to the same column?
Thanks!
public class Submission
{
[Key]
public Int32 SubmissionId { get; set; }
public DateTime Created { get; set; }
public Int32 ChallengeId { get; set; }
[ForeignKey("ChallengeId")]
public virtual Challenge Challenge { get; set; }
public String YouTubeVideoCode { get; set; }
public virtual IList<SubmissionVote> Votes { get; set; }
}
public class Challenge
{
[Key]
public Int32 ChallengeId { get; set; }
[Required]
public String ChallengeName { get; set; }
public virtual IList<Submission> Submissions { get; set; }
public Int32? OverallWinnerId { get; set; }
[ForeignKey("OverallWinnerId")]
public virtual Submission OverallWinner { get; set; }
}
I think you could benefit from just using the conventions and also using the shorthand keywords as data types. I think the error is because you have annotated the proxy with a ForeignKey attribute. Try this
public class Submission
{
public int SubmissionId { get; set; }
public DateTime Created { get; set; }
public int ChallengeId { get; set; }
public string YouTubeVideoCode { get; set; }
public virtual Challenge Challenge { get; set; }
public virtual IList<SubmissionVote> Votes { get; set; }
}
public class Challenge
{
public int ChallengeId { get; set; }
[Required]
public string ChallengeName { get; set; }
public int? OverallWinnerId { get; set; }
public virtual Submission OverallWinner { get; set; }
public virtual IList<Submission> Submissions { get; set; }
}
I'm pretty sure that Entity Framework uses a convention based approach, and the easiest way to fix this is to use the Id name instead of ChallengeId and SubmissionId
public class Submission
{
[Key]
public Int32 Id { get; set; }
public DateTime Created { get; set; }
public Int32 ChallengeId { get; set; }
[ForeignKey("ChallengeId")]
public virtual Challenge Challenge { get; set; }
public String YouTubeVideoCode { get; set; }
public virtual IList<SubmissionVote> Votes { get; set; }
}
public class Challenge
{
[Key]
public Int32 Id { get; set; }
[Required]
public String ChallengeName { get; set; }
public virtual IList<Submission> Submissions { get; set; }
public Int32? OverallWinnerId { get; set; }
[ForeignKey("OverallWinnerId")]
public virtual Submission OverallWinner { get; set; }
}

Categories

Resources