I'm new to Entity Framework and I've run into some problems while trying to implement my ERD Code First. The situation is as follows:
ERD
A product has a group of questions (QuestionGroup). A QuestionGroup has multiple questions and can belong to multiple Questionaires. A Questionaire basically has a questiongroup and a questionorder. The questionorder is supposed to keep the position of a question within that questionaire. The Questionaire table is needed because a QuestionGroup can have multiple questionorders, and a questionorder can belong to multiple questiongroups.
Because I'm trying my best to keep this post succinct I won't post all my classes, unless you ask to see them. The Entity classes I've made look like this:
public class Question
{
[Key]
public int Id { get; set; }
[MaxLength(2000)]
[Required]
public string Text { get; set; }
public Answer Answer { get; set; }
public QuestionType Type { get; set; }
public ICollection<QuestionAnswerOption> Options { get; set; }
public ICollection<QuestionOrder> Orders { get; set; }
[ForeignKey("FollowupQuestion")]
public int QuestionId { get; set; }
public virtual Question FollowupQuestion { get; set; }
[ForeignKey("Questiongroup")]
public int QuestionGroupId { get; set; }
public virtual QuestionGroup Questiongroup { get; set; }
}
public class QuestionOrder
{
[Key]
public int Id { get; set; }
public int Position { get; set; }
[ForeignKey("Question")]
[Required]
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
[ForeignKey("Questionaire")]
[Required]
public int QuestionaireId { get; set; }
public virtual Questionaire Questionaire { get; set; }
}
public class Product
{
[Key]
public int Id { get; set; }
[MaxLength(150)]
[Required]
[Index(IsUnique = true)]
public string Name { get; set; }
[MaxLength(500)]
public string Summary { get; set; }
[MaxLength(500)]
public string Examples { get; set; }
public virtual QuestionGroup QuestionGroup { get; set; }
}
public class QuestionGroup
{
[Key]
public int Id { get; set; }
public ICollection<Question> Questions { get; set; }
[ForeignKey("Product")]
public int ProductId { get; set; }
public virtual Product Product { get; set; }
}
public class Questionaire
{
[Key]
public int Id { get; set; }
public QuestionGroup Group { get; set; }
public QuestionOrder Order { get; set; }
}
The errors I'm getting look like this:
QuestionGroup_Product_Source: : Multiplicity is not valid in Role 'QuestionGroup_Product_Source' in relationship 'QuestionGroup_Product'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
QuestionOrder_Questionaire_Source: : Multiplicity is not valid in Role 'QuestionOrder_Questionaire_Source' in relationship 'QuestionOrder_Questionaire'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
QuestionType_Question_Source: : Multiplicity is not valid in Role 'QuestionType_Question_Source' in relationship 'QuestionType_Question'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
The question we've arrived at here is:
Does anyone here know of a way to fix the relations between my tables? Maybe my ERD needs some improvements too, but I think the problem is that I'm missing a few things with my Code First implementation.
what about this design for you;)
public class Customer
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CustomerId { get; set; }
public string CompanyName { get; set; }
public virtual ICollection<ContactInfo> ContactInfoes { get; set; }
public virtual ICollection<ProductQuestionaireReport> Reports { get; set; }
}
public class ContactInfo
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ContactInfoId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Telephone { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
public class ProductQuestionaireReport
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ProductQuestionaireReportId { get; set; }
[ForeignKey("Product")]
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public virtual QuestionaireResult Result { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
public bool Haste { get; set; }
public string Status { get; set; }
public string Comment { get; set; }
}
public class QuestionaireResult
{
[Key, ForeignKey("ProductQuestionaireReport")]
public int ProductQuestionaireReportId { get; set; }
[ForeignKey("Questionaire")]
public int QuestionaireId { get; set; }
public virtual Questionaire Questionaire { get; set; }
public DateTime SurveyCreated { get; set; }
public Double Costs { get; set; }
public Double FunctionPoints { get; set; }
public virtual ProductQuestionaireReport ProductQuestionaireReport { get; set; }
public virtual ICollection<QuestionaireAnswer> Answers { get; set; }
}
public class Product
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ProductId { get; set; }
public string Name { get; set; }
public string Summary { get; set; }
public string Examples { get; set; }
public virtual ICollection<Questionaire> Questionaires { get; set; }
public virtual ICollection<ProductQuestionaireReport> Reports { get; set; }
}
public class QuestionaireAnswer
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int QuestionaireAnswerId { get; set; }
[ForeignKey("QuestionaireResult")]
public int QuestionaireResultId { get; set; }
public virtual QuestionaireResult QuestionaireResult { get; set; }
[ForeignKey("QuestionaireQuestion")]
public int QuestionaireId { get; set; }
public virtual QuestionaireQuestion QuestionaireQuestion { get; set; }
[ForeignKey("Answer")]
public int AnswerId { get; set; }
public virtual QuestionOption Answer { get; set; }
public string Text { get; set; }
public virtual ICollection<string> Files { get; set; }
}
public class Questionaire
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int QuestionaireId { get; set; }
[ForeignKey("Product")]
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public virtual ICollection<QuestionaireQuestion> QuestionaireQuestions { get; set; }
public virtual ICollection<QuestionaireResult> Results { get; set; }
}
public class Question
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int QuestionId { get; set; }
[ForeignKey("ParentQuestion")]
public int ParentQuestionId { get; set; }
public virtual Question ParentQuestion { get; set; }
public virtual QuestionType QuestionType { get; set; }
public virtual ICollection<QuestionOption> Options { get; set; }
}
public class QuestionType
{
[Key, ForeignKey("Question")]
public int QuestionId { get; set; }
public string Text { get; set; }
public bool IsOpenQuestion { get; set; }
public virtual Question Question { get; set; }
}
public class QuestionOption
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int QuestionAnswerOptionId { get; set; }
[ForeignKey("Question")]
public int QuestionId { get; set; }
public string Text { get; set; }
public virtual Question Question { get; set; }
}
public class QuestionaireQuestion
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int QuestionaireQuestionId { get; set; }
[ForeignKey("Questionaire")]
public int QuestionaireId { get; set; }
public virtual Questionaire Questionaire { get; set; }
[ForeignKey("Question")]
public int QuestionId { get; set; }
public int DisplayOrder { get; set; }
public virtual Question Question { get; set; }
}
also you must add this to OnModelCreating
modelBuilder.Entity<Customer>().HasMany(c => c.ContactInfoes)
.WithRequired(i => i.Customer).HasForeignKey(i => i.CustomerId).WillCascadeOnDelete(false);
modelBuilder.Entity<Question>().HasMany(q => q.Options)
.WithRequired(o => o.Question).HasForeignKey(o => o.QuestionId).WillCascadeOnDelete(false);
modelBuilder.Entity<QuestionaireResult>().HasMany(r => r.Answers)
.WithRequired(a => a.QuestionaireResult).HasForeignKey(o => o.QuestionaireResultId).WillCascadeOnDelete(false);
check it and feedback me ...
Related
How can I use a primary key as a foreign key of another table's in two columns.
public class ResumeSharing
{
[Key]
public int ResumeSharingId { get; set; }
[ForeignKey("AppliedJobs")]
public int AppliedJobId { get; set; }
public virtual AppliedJob AppliedJobs { get; set; }
public bool OwnCompany { get; set; }
[Display(Name = "RecruiterFrom")]
public int RecruiterId { get; set; }
public virtual Recruiter Recruiters { get; set; }
[Display(Name = "RecruiterTo")]
public int RecruiterId { get; set; }
public virtual Recruiter Recruiters { get; set; }
[ForeignKey("Companies")]
public int CompanyId { get; set; }
public virtual Company Companies { get; set; }
public string SharedFiles { get; set; }
}
I want to call RecruiterId twice in this table. How can I do this?
you have to add navigation properties
public class ResumeSharing
{
[Key]
public int ResumeSharingId { get; set; }
[ForeignKey("AppliedJob")]
public int AppliedJobId { get; set; }
public virtual AppliedJob AppliedJob { get; set; }
public bool OwnCompany { get; set; }
[Display(Name = "RecruiterFrom")]
public int RecruiterFromId { get; set; }
[ForeignKey(nameof(RecruiterFromId))]
[InverseProperty("RecruiterFroms")]
public virtual Recruiter RecruiterFrom { get; set; }
[Display(Name = "RecruiterTo")]
public int RecruiterToId { get; set; }
[ForeignKey(nameof(RecruiterToId))]
[InverseProperty("RecruiterTos")]
public virtual Recruiter RecruiterTo { get; set; }
[ForeignKey("Company")]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
public string SharedFiles { get; set; }
}
public class Recruiter
{
[Key]
public int Id { get; set; }
[InverseProperty(nameof(ResumeSharing.RecruiterFrom))]
public virtual ICollection<Recruiter> RecruiterFroms { get; set; }
[InverseProperty(nameof(ResumeSharing.RecruiterTo))]
public virtual ICollection<Recruiter> RecruiterTos { get; set; }
}
I'm trying to create a Friendship mapping table that has 2 FK's that originate from the same class (User and SportsFacility)
Here are my model classes.
public partial class User
{
[Key]
public int Id { get; set; }
[Required]
public int AcountId { get; set; }
[Required]
[MaxLength(20)]
//[Column(TypeName = "varchar")]
public string Login { get; set; }
[Required]
[MaxLength(20)]
public string Name { get; set; }
[Required]
public string Password { get; set; }
public virtual ICollection<CheckQueue> ChecksQueue { get; set; }
public virtual ICollection<BookedEvent> BookedEvents { get; set; }
}
public partial class SportsFacility
{
public SportsFacility()
{
ChecksQueue = new List<CheckQueue>();
BookedEvent = new List<BookedEvent>();
}
[Key]
public int Id { get; set; }
[Required]
[MaxLength(30)]
public string Name { get; set; }
[Required]
public int PnH_Id { get; set; }
[Required]
[MaxLength(70)]
public string Address { get; set; }
public int City_Id { get; set; }
[ForeignKey("City_Id")]
public virtual City City { get; set; }
public virtual ICollection<CheckQueue> ChecksQueue { get; set; }
public virtual ICollection<BookedEvent> BookedEvent { get; set; }
}
public partial class CheckQueue
{
[Key]
public int Id { get; set; }
public DateTime StartCheckTime { get; set; }
[Required]
public string CheckParams { get; set; }
public string Error { get; set; }
public bool IsDeleted { get; set; }
public int User_Id { get; set; }
[ForeignKey("User_Id")]
public virtual User User { get; set; }
public int SportsFacility_Id { get; set; }
[ForeignKey("SportsFacility_Id")]
public virtual SportsFacility SportsFacility { get; set; }
[Index]
public DateTime? LastCheck { get; set; }
}
public partial class BookedEvent
{
[Key]
public int Id { get; set; }
public DateTime BookDate { get; set; }
[Required]
public string CheckParams { get; set; }
public string Error { get; set; }
public bool IsDeleted { get; set; }
public int User_Id { get; set; }
[ForeignKey("User_Id")]
public virtual User User { get; set; }
public int SportsFacility_Id { get; set; }
[ForeignKey("SportsFacility_Id")]
public virtual SportsFacility SportsFacility { get; set; }
}
I tried override the OnModelCreating method in the DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<City>();
modelBuilder.Entity<SportsFacility>();
modelBuilder.Entity<User>();
modelBuilder.Entity<CheckQueue>();
modelBuilder.Entity<BookedEvent>();
base.OnModelCreating(modelBuilder);
}
This causes a new error message to be displayed.
Additional information: The entity types 'BookedEvent' and 'CheckQueue' cannot share table 'CheckQueues' because they are not in the same type hierarchy or do not have a valid one to one foreign key relationship with matching primary keys between them.
Any help would be greatly appreciated.
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'm working with code first for a ecommerce project,
I have 2 classes: Category and Products
Relationship is one to many, Category has many products,
I want to make the foreign key as required (not null) so, if I add a product, I must enter the categoryid.
When I do so, I get this error:
Introducing FOREIGN KEY constraint 'FK_dbo.Products_dbo.Categories_categoryId' on table 'Products' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Any ideas?
public class Category :IObjectWithState
{
[Key]
public int CategoryId { get; set; }
[Required]
public string Discription { get; set; }
public string Notes { get; set; }
public int ParentCategoryId { get; set; }
public virtual ICollection<Product> Products { get; set; }
public virtual ICollection<Discount> Discounts { get; set; }
public virtual ICollection<ProductList> ProductLists { get; set; }
[NotMapped]
public State state { get; set; }
}
public class Product :IObjectWithState
{
[Key]
public int ProductId { get; set; }
[Required]
public string ProductName { get; set; }
[Required]
public string ShortDiscription { get; set; }
public string LongDiscription { get; set; }
[Required]
public bool Active { get; set; }
[Required]
public int categoryId { get; set; }
[ForeignKey("categoryId")]
public Category Category { get; set; }
public ICollection<ProductImage> ProductImage { get; set; }
public ICollection<Discount> Discount { get; set; }
public ICollection<Discussion> Duscussion { get; set; }
public ICollection<ProductAttributeValue> ProductAttributeValue { get; set; }
public ICollection<ProductListItem> ProductListItem { get; set; }
public ICollection<ProductSKU> ProductSKU { get; set; }
public ICollection<RelatedProduct> RelatedProduct { get; set; }
public ICollection<Review> Review { get; set; }
public ICollection<ShoppingCart> ShoppingCart { get; set; }
}
i set cascadeDelete: to false in the Migration class
Table 1: Articles
Table 2: ArticleCategories
how do I represent the relationship between the two tables which is a 1->1 relationship:
I can do the following, but I'm not sure it's the correct way :
public class Article
{
public int ArticleIndex { get; set; }
public int Category { get; set; }
public Guid User { get; set; }
public int Parent { get; set; }
public int Level { get; set; }
public int Order { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateExpires { get; set; }
public bool Show { get; set; }
public string Title { get; set; }
public string TitleHtml { get; set; }
public string Content { get; set; }
public string ContentHtml { get; set; }
public string ShortTitle { get; set; }
public ArticleCategory Category { get; set; }
}
public class ArticleCategory
{
public int CategoryIndex { get; set; }
public string Name { get; set; }
}
By convention, Code First expects an Id property for each class/table. Then you can do something like this:
public class Article
{
public int Id { get; set; }
public int ArticleIndex { get; set; }
public int Category { get; set; }
public Guid User { get; set; }
public int Parent { get; set; }
public int Level { get; set; }
public int Order { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateExpires { get; set; }
public bool Show { get; set; }
public string Title { get; set; }
public string TitleHtml { get; set; }
public string Content { get; set; }
public string ContentHtml { get; set; }
public string ShortTitle { get; set; }
public int ArticleCategoryId { get; set; }
public virtual ArticleCategory ArticleCategory { get; set; }
}
public class ArticleCategory
{
public int Id { get; set; }
public int CategoryIndex { get; set; }
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
Note the virtual keyword. EF Code First needs this so it can perform its magic behind the scenes.
Now, if you are working with an Article, you can get all it's category info by doing article.ArticleCategory, and if you have an ArticleCategory you can find out what article it refers to with articleCategory.Articles.Single().
For more info, see this article by Scott Gu:
http://weblogs.asp.net/scottgu/archive/2010/12/08/announcing-entity-framework-code-first-ctp5-release.aspx