I have two classes:
public class Address
{
public Guid Id { get; set; }
public virtual ICollection<ToAddressMessageLink> MessagesTo { get; set; }
public virtual ICollection<CopyAddressMessageLink> MessagesCopyTo { get; set; }
}
public class Message
{
public Guid Id { get; set; }
public virtual ICollection<ToAddressMessageLink> To { get; set; }
public virtual ICollection<CopyAddressMessageLink> CopyTo { get; set; }
}
And I need to save connection between them in a single table.
If I simply put many-to-many relation between, EF wouldn't realize what type of connection is actually set(table rows will be identical for them).
So I have to create a link class with a discriminator like following:
public class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
}
But it also doesn't work because I can't set link type/
So I have to use TPH here:
public abstract class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
}
public class CopyAddressMessageLink : AddressMessageLink
{
public virtual AddressDto Address { get; set; }
public virtual MessageDto Message { get; set; }
}
public class ToAddressMessageLink : AddressMessageLink
{
public virtual AddressDto Address { get; set; }
public virtual MessageDto Message { get; set; }
}
With a composite key:
HasKey(x=>new {x.AddressId, x.MessageId, x.LinkType});
But it doesn't work either, because EF:
"The foreign key component AddressId is not a declared property on type ToAddressMessageLink".
If I put AddressId and MessageId into derived class I can't set key because there is no component of it in base class.
What can I do it this situation?
If u have to classes, that you want to connect, you need to create a class that will connect yours two tables. And you did that there:
public class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
}
But you don't join virtual attributes. So you have to do like this.
In your tables definition:
public class Address
{
public Guid Id { get; set; }
public virtual ICollection<AddressMessageLink> AddressMessageLink { get; set; }
}
public class Message
{
public Guid Id { get; set; }
public virtual ICollection<AddressMessageLink> AddressMessageLink { get; set; }
}
And in AddressMessageLink object:
public class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
public virtual Address Address { get; set; }
public virtual Message Message { get; set; }
}
That will connect your tables as many to many.
Related
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.
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?
I am running my initial EF migration trying to create the database.
But only 3 of my 5 domains are being created as tables in the database. No errors occur during migration.
I try to run SeedData methods on run, but of course it stops when it tries to save data to the table that does not exist.
I am using EF7. I use DNX to run migrations.
Does anyone know why only 3 of the tables are being created?
Here are the 2 tables that did NOT get created:
// Enumclass, this is not a table
public enum MatchTypeEnum
{
Group, RoundOf32, RoundOf16, QuarterFinals, SemiFinals, BronzeFinal, Final
}
public partial class Match
{
[Key]
public Guid MatchId { get; set; }
public DateTime KickOffTime { get; set; }
public int? HomeScore { get; set; }
public int? AwayScore { get; set; }
public Guid HomeTeamId { get; set; }
public Guid AwayTeamId { get; set; }
public MatchTypeEnum MatchType { get; set; }
public Guid? GroupId { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
[ForeignKey("GroupId")]
public virtual Group Group { get; set; }
}
public enum MatchOutcomeEnum
{
H,A,D
}
public partial class Bet
{
[Key]
public Guid BetId { get; set; }
public Guid UserId { get; set; }
public Guid MatchId { get; set; }
public int? HomeScore { get; set; }
public int? AwayScore { get; set; }
public MatchOutcomeEnum? MatchOutcome{ get; set; }
public int? PointsCorrectScore { get; set; }
public int? PointsBonus { get; set; }
public int? MultiplyScoreWith { get; set; }
public int? TotalPointsBet { get; set; }
[ForeignKey("MatchId")]
public virtual Match MatchBettedOn { get; set; }
}
And here are the 3 classes that do get created:
public class Team
{
[Key]
public Guid TeamId { get; set; }
public string TeamName { get; set; }
public string TeamCountry { get; set; }
public Guid GroupId { get; set; }
public string LogoUrl { get; set; }
[ForeignKey("GroupId")]
public virtual Group TeamGroup { get; set; }
}
public enum GroupEnum
{
GroupA, GroupB, GrooupC, GroupD,GroupE,GroupF, GroupG, GroupH, GroupI
}
/// <summary>
/// The group.
/// </summary>
public partial class Group
{
[Key]
public Guid GroupId { get; set; }
public GroupEnum GroupName { get; set; }
public int? NumberTeamsProceed { get; set; }
public virtual ICollection<Team> TeamsInGroup { get; set; }
public virtual ICollection<Match> MatchesInGroup { get; set; }
}
public class League
{
[Key]
public Guid LeagueId { get; set; }
public string LeagueName { get; set; }
public bool Public { get; set; }
public int LeagueNumber { get; set; }
public string LeagueLink { get; set; }
}
The DbContext:
public class CupBettingContext : DbContext
{
public CupBettingContext()
{
Database.EnsureCreated();
}
public DbSet<Group> Groups { get; set; }
public DbSet<Match> Matches { get; set; }
public DbSet<Bet> Bets { get; set; }
public DbSet<League> Leagues { get; set; }
public DbSet<Team> Teams { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connectionString = Startup.Configuration["Data:CupBettingContextConnection"];
optionsBuilder.UseSqlServer(connectionString);
base.OnConfiguring(optionsBuilder);
}
}
Thank you for your time :)
UPDATE:
It worked after I I removed the two lines from the class Match:
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
Strange that it ran the migration :/
If anyone is still reading this question, how can I add those virtual object without getting an error?
I have been up to trying to do some Entity Framework Code First, but I am stuck with the 'FOREIGN KEY constraint may cause cycles or multiple cascade paths.' problem.
Here are my classes:
public class Course
{
public Course()
{
this.Subject = new HashSet<Subject>();
this.Student = new HashSet<Student>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Shift { get; set; }
public int Room { get; set; }
public virtual ICollection<Subject> Subject { get; set; }
public virtual ICollection<Student> Student { get; set; }
}
public class Subject
{
public Subject()
{
this.Deliverable = new HashSet<Deliverable>();
}
public int Id { get; set; }
public string Name { get; set; }
public int StartsAt { get; set; }
public int FinishesAt { get; set; }
public System.TimeSpan Weekdays { get; set; }
public int CourseId { get; set; }
public int TeacherId { get; set; }
public virtual Course Course { get; set; }
public virtual Teacher Teacher { get; set; }
public virtual ICollection<Deliverable> Deliverable { get; set; }
}
public class Student : Person
{
public Student()
{
this.Deliverable = new HashSet<Deliverable>();
}
public decimal Average { get; set; }
public int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual ICollection<Deliverable> Deliverable { get; set; }
}
public class Teacher : Person
{
public Teacher()
{
this.Subject = new HashSet<Subject>();
}
public virtual ICollection<Subject> Subject { get; set; }
}
public class Deliverable
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Mark { get; set; }
public System.DateTime DeliveredDate { get; set; }
public bool Delivered { get; set; }
public System.DateTime AnnounceDate { get; set; }
public int SubjectId { get; set; }
public int StudentId { get; set; }
public virtual Subject Subject { get; set; }
public virtual Student Student { get; set; }
}
I think it's a reference looping error, but I can't realize the approach on how to resolve it. I'm using Web API and I'm able to change the model, so feel free to modify it please. Could this be resolved using FluentAPI?
Here is the exception. It is thrown the first time I have executed the application:
'Introducing FOREIGN KEY constraint 'FK_dbo.Students_dbo.Courses_CourseId' on table 'Students' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.'
You have to use Fluent-API to disable delete / update. To do this, modify the OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Course>().HasMany(c => c.Student).WillCascadeOnDelete(false);
}
I'm not sure if it's the Course class or the Student class who causes issues, if this is not working, try to do a "WillCascadeOnDelete(false)" on your Student class.
I am creating my first asp.net mvc3 application. I'm using code first methodology. I have the following models:
public class FootballGame
{
[Key]
public Guid id_FootballGame { get; set; }
[ForeignKey("FootballGame")]
public Guid? FK_id_FootballGame { get; set; }
public virtual FootballGame PreviousFootballGame { get; set; }
[ForeignKey("FootballTeam")]
public Guid id_FootballTeam_owner { get; set; }
public virtual FootballTeam FootballTeamOwner { get; set; }
[ForeignKey("FootballTeam")]
public Guid id_FootballTeam_guest { get; set; }
public virtual FootballTeam FootballTeamGuest { get; set; }
}
public class FootballTeam
{
[Key]
public Guid id_FootballTeam { get; set; }
public string teamName { get; set; }
}
And I have the following class:
public class EFDbContext : DbContext
{
public EFDbContext() : base("name=EFDbContext") { }
public DbSet<FootballTeam> FootballTeams { get; set; }
public DbSet<FootballGame> FootballGames { get; set; }
}
Unfortunately, there is an exception:
The ForeignKeyAttribute on property 'FK_id_FootballGame' on type
'Bd.Domain.FootballGame' is not valid. The navigation
property 'FootballGame' was not found on the dependent type
'Bd.Domain.FootballGame'. The Name value should be a valid
navigation property name.
I tried to remove these lines:
[ForeignKey("FootballGame")]
public virtual FootballGame PreviousFootballGame { get; set; }
However, another exception to appear:
The ForeignKeyAttribute on property 'id_FootballTeam_owner' on type
'Bd.FootballGame' is not valid. The navigation property 'FootballTeam'
was not found on the dependent type 'Bd.FootballGame'. The Name value
should be a valid navigation property name.
I look forward to any help.
Regards, Denis.
Try this:
public class FootballGame
{
[Key]
public Guid id_FootballGame { get; set; }
public Guid? FK_id_FootballGame { get; set; }
[ForeignKey("FK_id_FootballGame")]
public virtual FootballGame PreviousFootballGame { get; set; }
public Guid id_FootballTeam_owner { get; set; }
[ForeignKey("id_FootballTeam_owner")]
public virtual FootballTeam FootballTeamOwner { get; set; }
public Guid id_FootballTeam_guest { get; set; }
[ForeignKey("id_FootballTeam_guest")]
public virtual FootballTeam FootballTeamGuest { get; set; }
}