Junction table with additional payload columns in EF4 CTP4 Code First - ctp4

I have the following tables:
WOPartList (defines parts that have 1 or more Part_Size)
WOPartSize (defines sizes that have 1 or more Part_Size)
Part_Size (junction table as addt payload columns such as sku, on_hand etc...)
Here are the POCO classes for the DAL:
// Real World Scenario:
// PartList Related to Part_Size Related to PartSize
//
// #8 Stainless Lag Bolt sku- 87234018 size- 2 x 1/2
// on hand- 214
// on order- 12
// #8 Stainless Lag Bolt sku- 87234199 size- 3 x 1/2
// on hand- 81
// on order- 18
// #10 Stainless Lag Bolt sku- 87237835 size- 1 x 1/2
// on hand- 11
// on order- 14
// #10 Stainless Lag Bolt sku- 87237835 size- 2 x 1/2
// on hand- 11
// on order- 14
// #10 Stainless Lag Bolt sku- 87237835 size- 3 x 1/2
// on hand- 11
// on order- 14
// So the idea is to be able to create a size once and use it many times
// for many different parts... But I need to keep specific statistics for
// each size of a part...
// How do I tell the Model that Part_Size is a many-to-many junction table
// between WOPartSize and WOPartsList as well ?
public class WOPartSize
{
public int WOPartSizeId { get; set; }
public DateTime tadded { get; set; }
public string size { get; set; }
// Nav Collections
public virtual ICollection<Part_Size> Parts { get; set; }
}
public class Part_Size // Junction Table
{
public int WOPartSizeMMId { get; set; }
public string part_no { get; set; }
public string part_descr { get; set; }
public string sku { get; set; }
public decimal cost_each { get; set; }
public decimal price_each { get; set; }
public int on_hand { get; set; }
public int on_trucks { get; set; }
public int on_order { get; set; }
// Put ICollections<> here ?
}
public class WOPartsList
{
public int WOPartsListId { get; set; }
public DateTime tadded { get; set; }
public string part_descr { get; set; }
// Nav References
public virtual WOPartType PartType { get; set; }
public int WOPartTypeId { get; set; }
public virtual ICollection<Part_Size> Sizes { get; set; }
}
How do I configure the junction table ? Annotations ? Fluent API ? My main trouble is getting the additional payload fields in junction table... Otherwise I would simply let EF generate the table for me and have NO POCO class...

Related

How to establish one-to-many relationship for a code-first approach?

I'm trying to build a recipe app for my spouse. I'm trying to set it up so she can add new recipes to the database as the app grows.
When adding new recipe, she will have three drop-down to pick from to construct her new recipe ingredients. First one will contain a list of ingredients that she can choose from, the second one a list of measuring units and the third one a list of quantities.
Here is what I got so far. Am I heading in the right direction or am I off? I'm using Entity Framework with a code-first approach:
public class Recipes
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
}
public class Units model
{
[Key]
public int Id { get; set; }
public string UnitName { get; set; }
}
public class UnitQty
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class IngredientsModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class RecipeIngredients
{
public int Id { get; set; }
public int RecipesId { get; set; }
[ForeignKey("RecipesId")]
public Recipes Recipes { get; set; }
public int IngredientsModelId { get; set; }
[ForeignKey("IngredientsModelId")]
public IngredientsModel IngredientsModel { get; set; }
public int UnitQtyId { get; set; }
[ForeignKey("UnitQtyId")]
public UnitQty UnitQty { get; set; }
public int UnitsModelId { get; set; }
[ForeignKey("UnitsModelId")]
public UnitsModel UnitsModel { get; set; }
}
After creating the table, controller and the views, this is what I get in the recipe ingredients index view.
Any suggestion will be more than welcome please and thank you
RecipeIngredient class's view
First of all. You are over engineering your domain model. On relational databases Join is bottleneck you should prevent from joins if it doesn't helps you.
public class Recipt
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public ICollection<RecipeIngredient> Ingredients { get; set; }
}
public class IngredientModel
{
public int Id { get; set; }
public string Name { get; set; }
public IngredientUnit UnitType { get; set; } // Unit model is best to be added here. if it doesn't change in a single IngredientModel.
}
public class RecipeIngredient
{
public int Id { get; set; }
public int UnitQuantiy { get; set; } // No need to more classes.
public IngredientModel Model { get; set; }
public Recipt Recipt { get; set; }
}
public Enum IngredientUnitType // Same Unit Model but less database relation as its small finite collection.
{
Killogram,
Count,
....
}
and according to the Microsoft documents its best to use fluentApi configuration for the relations.
Override this method in your Context:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Recipt>.HasMany(P => P.Ingredients).WithOne(P => P.Recipt);
builder.Entity<RecipeIngredient>.HasOne(P => P.Model);
// There is no need to explicit foreign key definition. but you can explicitly define your foreign keys.
}
And for the last part. in Views you can use extra models called ViewModels.
As above domain turned to a minimal domain you just need to pass a list of IngredientModels to your view to complete your View.

EF Core only creates one self-referencing foreign key instead of 2

I am trying to create a model to represent missions in a game. When a mission is completed, another mission is played depending on which team won the mission. For example Mission1, if TeamA wins then you play Mission2, if TeamB wins then you play Mission3.
For each mission I want two self-referencing columns, TeamAWinMission and TeamBWinMission, which hold the foreign key to another mission.
The migrations only seem to recognise a single self-reference in the model.
This will create a column for TeamAWinMission:
public class Mission
{
public int Id { get; set; }
public string Name { get; set; }
public Mission TeamAWinMission{ get; set; }
}
This will only create a column for TeamBWinMission:
public class Mission
{
public int Id { get; set; }
public string Name { get; set; }
public Mission TeamAWinMission{ get; set; }
public Mission TeamBWinMission{ get; set; }
}
How can I make the migration generate columns/foreign keys for both of these?
Edit: Was able to resolve this with InverseProperty from https://stackoverflow.com/a/46832490/11575271
It seems that there is one-to-one self-reference relationship in Mission model , you could try to define the [ForeignKey]in your model like below :
public class Mission
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("TeamAWinMission")]
public int? TeamAWinMissionId { get; set; }
public Mission TeamAWinMission { get; set; }
[ForeignKey("TeamBWinMission")]
public int? TeamBWinMissionId { get; set; }
public Mission TeamBWinMission { get; set; }
}
Then use Include attribute to load related data in the controller :
public IActionResult Mission()
{
var result = _context.Missions
.Include(m => m.TeamAWinMission)
.Include(m => m.TeamBWinMission)
.ToList();
return View(result);
}
Reference : https://learn.microsoft.com/en-us/ef/core/querying/related-data

What should I type in migration if I want to multiply 2 values from two different tables ? ASP.NET MVC Entity Framework

This is what am I suppose to complete "Calculate total animal maintenance cost. Which is obtained by adding the food cost (food cost * animal weight), housing cost." I don't know how to do calculation for all (PetWeight from PetRescued Table)*(FoodCost from PetSpecies Table) and Insert it into my MaintenanceCost Table.
And
For example, I have 4 type of pet species which is Cat,Dog,Rabbit and Rodent. The HousingCost for the pets are 10,20,30,40.This is Table 1. For Table 2 which is the PetRescued, How do I calculate the sum of HousingCost for how many cats/dogs/.../... that I have in my PetRescued database and Insert it into my MaintenanceCost Table.
This is my PetRescued entity which is also one of the Table
public class PetRescued
{
public int Id { get; set; }
public string PetName { get; set; }
public int PetAge { get; set; }
public string PetGender { get; set; }
public double PetWeight { get; set; }
public DateTime? DateWhenRescued { get; set; }
public string PetBreedName { get; set; }
public PetSpecies PetSpecies { get; set; }
public byte PetSpeciesId { get; set; }
public PetSanctuary PetSanctuary { get; set; }
public byte PetSanctuaryId { get; set; }
}
This is my PetSpecies entity which consist of the FoodCost and also my second Table
public class PetSpecies
{
public byte Id { get; set; }
public string SpeciesName { get; set; }
public double FoodCost { get; set; }
public double HousingCost { get; set; }
}
This is my MaintenanceCost entity which is use to store the result from the calculation
public class MaintenanceCost
{
public byte Id { get; set; }
public double TotalFoodCost { get; set; }
public double TotalHousingCost { get; set; }
public double TotalVetBillCost { get; set; }
}
The query you need is something like this. It inserts one entity containing sum of all costs.
INSERT INTO MaintenanceCost (TotalFoodCost,TotalHousingCost,TotalVetBillCost)
Values (
(SELECT SUM(PetRescued.PetWeight * PetSpecies.FoodCost FROM PetRescued INNER JOIN PetSpecies ON PetRescued.PetSpeciesId = PetSpecies.Id)),
(SELECT SUM(PetSpecies.HousingCost FROM PetRescued INNER JOIN PetSpecies ON PetRescued.PetSpeciesId = PetSpecies.Id)),
"the amount of TotalVetBillCost"
)
However this approach is against one the basic rules of databases that is never store a data that can be retrieved from other data stored in the database. Also, It is clear that when the data in other two tables alter, this entity will no longer be valid.

Creating a score sheet in SQL

On my website, I have a score sheet that the user fills out. They will USUALLY have 10 items on a score sheet and each item will have its own score. I am wanting to design this in the best way for future expandability. What If I want to have more or less items on the score sheet in the future?
Here is what I have now:
public class Scoresheet712Item
{
public int ScoresheetItemId { get; set; }
public int ScoresheetId { get; set; }
public int DistanceAway { get; set; }
public int score { get; set; }
}
Is it better to do this or is it better to have all 10 scores and distances on the same row? I would rather have them in the same row because I can pull that one row directly in as a model. I originally thought to do it this way so I could easily vary how many slots there are on the score sheet, but it doesn't seem like there is much benefit really, specifically because I am using MVC development and I will always need the entire score sheet.
Please help, can I have all the data in one row for a score sheet and that be good practice?
Here is what I am trying to propose, it would be a little different though because each score DOES have a different purpose.:
public class Scoresheet
{
public int ScoresheetId { get; set; }
public int DistanceAway1 { get; set; }
public int score1 { get; set; }
public int DistanceAway2 { get; set; }
public int score2 { get; set; }
public int DistanceAway3 { get; set; }
public int score3 { get; set; }
public int DistanceAway4 { get; set; }
public int score4 { get; set; }
public int DistanceAway5 { get; set; }
public int score5 { get; set; }
public int DistanceAway6 { get; set; }
public int score6 { get; set; }
public int DistanceAway7 { get; set; }
public int score7 { get; set; }
public int DistanceAway8 { get; set; }
public int score8 { get; set; }
public int DistanceAway9 { get; set; }
public int score9 { get; set; }
public int DistanceAway10 { get; set; }
public int score10 { get; set; }
}
Like this?
public class Scoresheet712
{
public int Scoresheet712ID { get; set; }
public virtual ICollection<Scoresheet712Item> Scoresheet712Items { get; set; }
}
I am inclined to agree with #Stephen Muecke to be flexible and extendable you really need two sql tables.
public class Scoresheet
{
public int ScoresheetId { get; set; }
public string ScoresheetName { get; set; }
public ICollection<ScoresheetItem> ScoresheetItems { get; set; }
}
And
Public class ScoresheetItem
{
public int ScoresheetItemId { get; set; }
public int Score { get; set; }
public int Distance { get; set; }
//Navigation properties
public int ScoresheetId { get; set; }
public Scoresheet Scoresheet { get; set; }
{
This will let you build a new Scoresheet as needed with as many or as few items as you want. The example below shows the usage.
//Create a new Scoresheet
Scoresheet scoresheet712 = new Scoresheet()
{
ScoresheetName = "Score Sheet 712",
ScoresheetItems = new List<ScoresheetItem>()
};
//Add a ScoresheeItem to Scoresheet
scoresheet712.ScoresheetItems.Add(new ScoreSheetItem()
{
Score = 10,
Distance = 150
});
Remember that on your View you do not need to use your Data Model you can always add a Data Transfer Object (Scoresheet_DTO) and make the flat structure for your score sheet if it really does make displaying it easier/better, just be sure to use nullable integers.
UPDATE MANY-TO-MANY RELATIONSHIP
For a many-to-many relationship if setup correctly in code it will automatically create the joining table. The Scoresheet class would remain the same but the ScoresheetItem class would have a small change to the Relationship/Navigation properties.
Public class ScoresheetItem
{
public int ScoresheetItemId { get; set; }
public int Score { get; set; }
public int Distance { get; set; }
//Navigation properties
public ICollection<Scoresheet> Scoresheet { get; set; }
{
For further help I would recommend taking a look at this Entity Framework Tutorial

How to build a self referencing table with composite key in fluent api and EF

I'm building a hierarchical Database with "closure table" to build the tree
It is a self referencing table, and the two keys should become the primary key.
The Problem is, I end up with 5 columns, when I expect only 3.
Here is what I tried:
public class Tree
{
public int TaskId { get; set; }
public Task Task { get; set; } //navigation Property to TaskTable
public int? ChildId { get; set; }
public Tree Child { get; set; } //navigation Property
public int Length { get; set; } //Length
}
public class Task
{
public int TaskId { get; set; }
public virtual ICollection<Tree> Trees { get; set; }
}
modelBuilder
.Entity<Task>()
.HasKey(t => t.TaskId);
modelBuilder
.Entity<Tree>()
.HasKey(a => new { a.TaskId, a.ChildId });
The result is a table with 5 columns:
TaskId
ChildId
Length
Child_TaskId
Child_ChildId
I expected:
TaskId
ChildId
Length
I'm guessing some fluent api missing, but I couldn't get to work otherwise ?