Adding model to database that has virtual relations - c#

I have this scenario where i have a model named Category that has a One-To-One relation with another model named Question. The following is the code for both of the models:
Category:
public class Category
{
[Key]
[Required]
public int Id { get; set; }
[Required]
public int QuestionRef { get; set; }
[Required]
public string Name { get; set; }
[Required]
public DateTime Timestamp { get; set; }
public virtual Question Question { get; set; }
}
Question:
public class Question
{
[Required]
[Key]
public int Id { get; set; }
[Required]
public int CategoryRef { get; set; }
[Required]
public int QuestionLevel { get; set; }
[Required]
public string QuestionText { get; set; }
[Required]
public DateTime Timestamp { get; set; }
public virtual Category Category { get; set; }
}
Snippet from OnModelCreating:
modelBuilder.Entity<Category>().HasOne(x => x.Question).WithOne(x => x.Category).HasForeignKey<Question>(x => x.CategoryRef);
modelBuilder.Entity<Question>().HasOne(x => x.Category).WithOne(x => x.Question).HasForeignKey<Category>(x => x.QuestionRef);
I seem to have come across a problem that i cannot understand how to tackle. Basically, i do not have a clue of how i can insert this relation into the database (SQL Server).
The question is do i have to implicitly write in the repository that
NewCategory.Question = QuestionInput;
or does it automatically generate itself given the relations i have implied in the OnModelCreating?

Related

EF Include is not working! returning null in a 1 to many relationship

i am trying to display a list of cities with a country, a 1 to many relation.
I created the models for both of them:
City model
[Key]
public int ID_Cidade { get; set;
public int ID_Pais { get; set; }
public RH_Pais Pais { get; set; }
public string Nome { get; set; }
public Boolean Capital { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public string Autor { get; set; }
public int OrdemCidade { get; set; }
public List<RH_Escritorios> Escritorios { get; set; }
Country model
[Key]
public int ID_Pais { get; set; }
public int ID_Moeda { get; set; }
public RH_Moeda Moeda { get; set; }
public string Nome { get; set; }
public string Nome_completo { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public string Autor { get; set; }
public int OrdemPais { get; set; }
public List<RH_Cidades> Cidades { get; set; }
public List<RH_Idioma_Pais> Idiomas { get; set; }
and then i used fluent API to create the relationship
modelBuilder.Entity<RH_Cidades>()
.HasOne(m => m.Pais)
.WithMany(m => m.Cidades)
.HasForeignKey(m => m.ID_Pais);
and somehow when i generate the controller with EF, and i go to see the cities it causes a null error... this is because it has a include of the country when im trying to get the cities..
var rH_EntitiesContext = _context.RH_Cidades.Include(r => r.Pais).ToList();
The most annoying part is that i have the exact same situation in another relationship, with 1 to many and the include and it works perfectly!!
I have read and read my code for hours by now and i cannot see why the Include is giving me that error when in the offices controller with the same situation works...
Any help is appreciated!!!

Entity Framework map one to many to one

I got into trouble in mapping tables with Entity Framework with the relationship is one to many to one.
To make it clear, here's the illustration of table classes
public class Human
{
[Key]
public long ID { get; set; }
[Required(ErrorMessage = "must not be empty!", AllowEmptyStrings = false)]
public string HumanName { get; set; }
public virtual ICollection<HumanFootwear> HumanFootwears { get; set; }
}
The Human footwear class (for grouping)
public class HumanFootwear
{
[Key]
public long ID { get; set; }
[ForeignKey("HumanID"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual Human CHumans { get; set; }
public long HumanID { get; set; }
[ForeignKey("FootwearID"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual Footwear Footwears { get; set; }
public long FootwearID { get; set; }
}
The footwear table class
public class Footwear
{
[Key]
public long ID { get; set; }
[Required(ErrorMessage = "must not be empty!", AllowEmptyStrings = false)]
public string BrandName { get; set; }
}
I'm trying with the fluent API method, but I can't get make it to work
modelBuilder.Entity<Human>()
.HasKey(key => key.ID)
.HasMany(hm => hm.Footwear)
.WithMany(wm => wm.Human)
.Map(map =>
{
map.MapLeftKey("")
});
I get a syntax error on "with many human",
Cannot convert single Human class to ICollection<Human>
Am I doing it wrong? Should I map the human footwear instead?

Entity Framework Migration - Alter Table Statement Conflicted with Foreign Key Constraint

I am creating a blog of sorts with C#/.NET 4.5 framework using EF code-first migrations.
Things have been going well up until adding a third relationship into my main class.
I have a "story" class (kind of like a "post" for a blog) where I have the author as the user who's logged in (set in the controller), a title, some content, the date it was created, and a genre and type of story.
public class Story
{
public int Id { get; set; }
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
[Required]
[StringLength(50)]
public string Title { get; set; }
[Required]
[MinLength(100), MaxLength(5000)]
public string Content { get; set; }
[Required]
public int GenreId { get; set; }
public Genre Genre { get; set; }
[Required]
public int StoryTypeId { get; set; }
public StoryType StoryType { get; set; }
public DateTime CreatedAt { get; set; }
}
I added storytypes as a property to the story. StoryType links to the StoryType model:
public class StoryType
{
public int Id { get; set; }
public string Name { get; set; }
}
I made sure to add my dbset to my application db context:
public DbSet<Genre> Genres { get; set; }
public DbSet<Story> Stories { get; set; }
public DbSet<StoryType> StoryTypes { get; set; }
I pretty much followed the same steps I used to create the relationship between the story and genre (which worked fine). Before I start building the StoryType controllers, I went into package-console and ran:
add-migration
that returned:
public partial class CreateTypeTable : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.StoryTypes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
AddColumn("dbo.Stories", "StoryTypeId", c => c.Int(nullable: false));
CreateIndex("dbo.Stories", "StoryTypeId");
AddForeignKey("dbo.Stories", "StoryTypeId", "dbo.StoryTypes", "Id", cascadeDelete: true);
}
public override void Down()
{
DropForeignKey("dbo.Stories", "StoryTypeId", "dbo.StoryTypes");
DropIndex("dbo.Stories", new[] { "StoryTypeId" });
DropColumn("dbo.Stories", "StoryTypeId");
DropTable("dbo.StoryTypes");
}
}
Glancing over it, I didn't see an issue, then ran:
update-database
in package-console.
Which returned:
Error Number:547,State:0,Class:16
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Stories_dbo.StoryTypes_StoryTypeId". The conflict occurred in database "aspnet-HiRatik.Stories-20180724043630", table "dbo.StoryTypes", column 'Id'.
I'm not sure what went wrong here. I did the same process with the Genre relationship and it worked. I didn't see a difference in the two.
because the StoryTypeId in the class Story dosen't accept null so you need to make the StoryTypeId nullable :
public class Story
{
public int Id { get; set; }
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
[Required]
[StringLength(50)]
public string Title { get; set; }
[Required]
[MinLength(100), MaxLength(5000)]
public string Content { get; set; }
[Required]
public int GenreId { get; set; }
public Genre Genre { get; set; }
public int? StoryTypeId { get; set; }
public StoryType StoryType { get; set; }
public DateTime CreatedAt { get; set; }
}
or you create first the table StoryType and you add elements to it and then add the StoryTypeId with default value:
public class Story
{
public int Id { get; set; }
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
[Required]
[StringLength(50)]
public string Title { get; set; }
[Required]
[MinLength(100), MaxLength(5000)]
public string Content { get; set; }
[Required]
public int GenreId { get; set; }
public Genre Genre { get; set; }
[[DefaultValue(1)]]
public int StoryTypeId { get; set; }
public StoryType StoryType { get; set; }
public DateTime CreatedAt { get; set; }
}
in this case you must update the database after creating StoryType and the after adding the StoryTypeId to the class Story
You can make the foreign key nullable by using a sign ?, like this: int?.
In my case, I was getting this because there was data in the table on which I was creating the foreign key that's why I was getting this error. And as we know foreign key is nullable.

How to define a table that its primary key is constructed from 2 foreign keys with EF code-first

I am using models to define my tables using EF code-first.
I have and Item model and an Order model.
Item:
public class Item
{
public int ItemID { get; set; }
[Required]
public int Price { get; set; }
[Required]
public int AmountLeft { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string FullDescription { get; set; }
[Required]
public DateTime PublishDate { get; set; }
public int CompanyID { get; set; }
public int CategoryID { get; set; }
// Navigation properties
public virtual Company Company { get; set; }
// Navigation properties
public virtual Category Category { get; set; }
}
Order model:
public class Order
{
public int OrderID { get; set; }
[Required]
public DateTime DeliveryDate { get; set; }
[Required]
public string Currency { get; set; }
[Required]
public int TotalAmount { get; set; }
public List<int> Items { get; set; }
public DateTime OrderDate { get; set; }
public int UserID { get; set; }
// Navigation properties
public virtual User user { get; set; }
}
I want to create another table which will be called ItemInOrder which will only have 2 fields: ItemID and OrderID.
the primary key would be these 2 foreign keys.
i tried to define this model:
public class ItemInOrder
{
public int OrderID { get; set; }
public int ItemID { get; set; }
// Navigation properties
public virtual Order order { get; set; }
public virtual Item item { get; set; }
}
But i got errors. i tried to put [Key] notation on both fields but still i got errors.
how will i be able to create the table i want?
When you need to create a table with composite PKs, you need to specify the order of you keys. There are two variants:
You could override the OnModelCreating method on your Context, and try with these Fluent Api configurations:
// Configure the primary keys for the ItemInOrder in the order you want
modelBuilder.Entity<ItemInOrder>()
.HasKey(t => new{t.OrderID,ItemID);
modelBuilder.Entity<ItemInOrder>()
.HasRequired(io=>io.Order)
.WithMany()
.HasForeigKey(io=>io.OrderID);
modelBuilder.Entity<ItemInOrder>()
.HasRequired(io=>io.Item)
.WithMany()
.HasForeigKey(io=>io.ItemID);
The second variant using Data Annotations should be this way:
[Key]
[Column(Order=1)]
[ForeignKey("Order")]
public int OrderID { get; set; }
[Key]
[Column(Order=2)]
[ForeignKey("Item")]
public int ItemID { get; set; }
EF will notice you want to create two relationships and it will do the job for you.

one to none-or-one relationship in ASP.NET MVC EF Code First

I'm new to .NET MVC and I'm struggling with using Code First with an existing database in which a table has a one to none-or-one (1 -> 0..1) relationship.
I have a report, which can have many sections, and each section can have many questions. Now here's the bit where I think I'm running into trouble... each question may have one answer or none.
I'm getting the following error:
System.Data.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role
'QuestionAnswer_Question_Source' in relationship
'QuestionAnswer_Question'. Because the Dependent Role properties are
not the key properties, the upper bound of the multiplicity of the
Dependent Role must be �*�.
Here are my model classes:
ModeratorReport.cs
public class ModeratorReport
{
[Key, Column(Order = 0)]
public int ModeratorReportID { get; set; }
[Key, Column(Order = 1)]
public string Status { get; set; }
public string FileYear { get; set; }
public string SessionCode { get; set; }
public string CentreNumber { get; set; }
public string SubjectNumber { get; set; }
public string PaperNumber { get; set; }
public string ModeratorNumber { get; set; }
public DateTime? DateModified { get; set; }
public virtual ICollection<AuditItem> Audit { get; set; }
}
Section.cs
public class Section
{
[Key]
public int SectionID { get; set; }
public string SectionEnglish { get; set; }
public string SectionWelsh { get; set; }
public virtual ICollection<Question> Questions { get; set; }
}
Question.cs
public class Question
{
[Key]
public int QuestionID { get; set; }
[ForeignKey("Section")]
public int SectionID { get; set; }
public string QuestionEnglish { get; set; }
public string QuestionWelsh { get; set; }
public string Type { get; set; }
public virtual Section Section { get; set; }
public virtual QuestionAnswer QuestionAnswer { get; set; }
}
QuestionAnswer.cs
public class QuestionAnswer
{
[Key]
public int AnswerID { get; set; }
[ForeignKey("ModeratorReport"), Column(Order = 0)]
public int ModeratorReportID { get; set; }
[ForeignKey("ModeratorReport"), Column(Order = 1)]
public string Status { get; set; }
[ForeignKey("Section")]
public int SectionID { get; set; }
[ForeignKey("Question")]
public int QuestionID { get; set; }
public string Answer { get; set; }
public virtual ModeratorReport ModeratorReport { get; set; }
public virtual Section Section { get; set; }
public virtual Question Question { get; set; }
}
I also have a one-to-many relationship with ModeratorReport and Audit but I don't think that is what is causing the error.
Any help would be appreciated.
Thanks.
The EF is complaining because it sounds like you are using an FK Association - which means that the QuestionID is a property of the Entity and there is a Question reference too - and you can't do this with FK Associations.
if you remove the QuestionID from QuestionAnswer it should work
public class QuestionAnswer
{
[Key,ForeignKey("Question")]]
public int AnswerID { get; set; }
[ForeignKey("ModeratorReport"), Column(Order = 0)]
public int ModeratorReportID { get; set; }
[ForeignKey("ModeratorReport"), Column(Order = 1)]
public string Status { get; set; }
[ForeignKey("Section")]
public int SectionID { get; set; }
public string Answer { get; set; }
public virtual ModeratorReport ModeratorReport { get; set; }
public virtual Section Section { get; set; }
public virtual Question Question { get; set; }
}
I would suggest you to use fluent mapping which is more clear:
modelBuilder.Entity<Question>()
.HasOptional(q => q.QuestionAnswer)
modelBuilder.Entity<QuestionAnswer>()
.HasRequired(qa => qa.Question)
Yes you should remove the QuestionId from the Answer entity in order to get it to work.
The fluent configuration then will be :
modelBuilder.Entity<Question>()
.HasOptional(qa => qa.QuestionAnswer)
Also, if you want to use a navigation property on the Answer to retrieve the correspondent question, I guess that an answer should not exists without a question. You can then enforce the Id of the answer to be both PK and FK with the QuestionId.
Add this to the configuration of the Answer :
modelBuilder.Entity<QuestionAnswer>()
.HasRequired(qa => qa.Question)

Categories