Create revision based on foreign key ef core - c#

I have two entities:
public class Car
{
public long Id { get; set; }
public List<CarConfiguration> CarConfigurations { get; set; }
}
and
public class CarConfiguration
{
public long Id { get; set; }
public long Revision { get; set; }
public long CarId { get; set; }
public Car Car { get; set; }
}
I want to auto-increment the revision based on the car, so for each car, the revision starts at 1, but when I add an additional CarConfiguration, I want the revision to be auto-incremented.
So the result of CarConfigurations should look something like that:
Id
CarId
Revision
1
1
1
2
1
2
3
2
1
4
1
3
Is there a way to configure ef-core like that?
I know I could handle that with a SQL trigger in the migration, but I want to let EF-Core do all the magic (at least let EF-Core add the SQL to the migration).

Related

EF model change one-to-one relationship to many-to-many relationship

I have two tables with one-to-one relationship.
public class Name
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Category { get; set; }
public int? NameId { get; set; }
[ForeignKey("NameId ")]
public virtual Name Name { get; set; }
}
I already have data in those tables.
I know the database relations are not supported to be changed.
Is it possible to change one-to-one relationships to many-to-many relationships?
What is the most suitable approach to overcome this requirement?
Yes, you can still change that, using migrations.
Step 1 is to create a linking table, like NameCategories, which looks something like this:
public class NameCategories
{
public int Id { get; set; }
public int NameId { get; set; }
public Name Name { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
Step 2 is to reference this table in the tables you already have. In Name it would look like this
public class Name
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<NameCategory> Categories { get; set; }
}
Step 3 is to add a migration. You'll have some AddColumn() and some DropColumn() statements. In between them, when all the add stuff was executed but the drops not yet, you can add SQL code to carry over all the existing relations into the newly created table. After that, the old data will be deleted by the DropColumn() code. In your example, this would look something like this
INSERT INTO NameCategories (NameId, CategoryId)
SELECT (n.Id, c.Id) FROM Names n
JOIN Categories c on c.NameId = n.Id
WHERE ..
You can execute the SQL in the migration like this:
var sql = #"...";
Sql(sql);
I hope this helps you out!

Calculated values on a ASP.NET Core with Angular App

I'm currently developing an application on ASP.NET Core with Angular using Code First Migration and SQL Server. Now I have following "problem". I have data models with properties which always be refreshed on any change. The difficulty is that it is often calculated based on data of other models.
As an example:
I have these models (this is a little bit simplified):
public class Dinner {
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Recipe> recipes {get; set; }
public Dinner ()
{
Recipes= new Collection<Recipe>();
}
}
public class Recipe {
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Ingredient> ingredients {get; set; }
public Recipe ()
{
Ingredients = new Collection<Ingredient>();
}
}
public class Ingredient {
public int Id { get; set; }
public Product Product { get; set; }
public int ProductId { get; set; }
public Recipe Recipe { get; set; }
public int RecipeId { get; set; }
public decimal Quantity { get; set; }
}
public class Product {
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Price> Prices { get; set; }
public Product()
{
Prices = new Collection<Price>();
}
}
public class Price {
public int Id { get; set; }
public decimal PricePerUnit { get; set; }
public Product Product { get; set; }
public int ProductId { get; set; }
}
I want to have
a calculated property for ingredient (which is the price for that specific quantity based on the price for the product)
a calculated property for recipe (the sum of all costs for all the ingredients)
a calculated property for dinner (the sum of all used recipes)
My question is: For best practice where should I do add this property?
Currently I calculate these properties on the app component by calculation the property of the used interface during the onInit() process. But this requires for example to load all the data up to prices to calculate the sum property of Dinner.
My goal is to have these sum property as up-to-date as possible but I would like to have the calculation (if possible) on SQL Server so I do need to load less data. Does this approach make sense? And how can I achieve that goal?
Looking at the model, it looks like you have three tables in your DB.
Ideally, you should keep these calculated values stored in DB.
This means that, when you are inserting a record for a dinner, you would add ingredients first, then calculate the total of all ingredients and insert the recipe. Likewise, calculate the total of all recipes and use the same while adding a Dinner. ALL THIS CALCULATION SHOULD HAPPEN IDEALLY INSIDE THE CONTROLLER(INSIDE REPOSITORY TO BE PRECISE).
Then, whenever you read the Dinner, you get the calculated values from the DB into your API.
What say?
You can add your calculations as calculated columns in SQL Server. The calculated columns would be marked as such in the EF Core model. When EF retrieves a Dinner, for example, the calculated dinner cost column will be computed in SQL Server and returned to EF Core without needing to retrieve the related tables.

Cyclic dependency check using EF Core

I have the following requirement whilst using EF Core 3. I have Exercises with (Id = 1 Pushup), (Id = 2 Squat), (Id = 3 Weight Lift) and users. Once one exercise is completed, one ore more new exercise(s) are created. A multilevel hierarcy can be created with n level.
I have an issue though that can cause cyclic dependencies to the exercices.
e.g Pushup (1) is completed. Squat (2) is created. Squat (2) is completed then Weight Lift (3) is created. There is also a dependency on Weight Lift (3) that once it is completed it creates Pushup(1) with leads to cyclic dependency and I need to avoid that.
I gave a very simple example. In my project, dependencies can go up to level 50 and I dont know how to check for cyclic reference and avoid them.
Below is the code:
public class Exercise
{
public Exercise()
{
ExerciseDependencyExercises = new HashSet<ExercisesDependency>();
ExerciseDependencyTargetExercises = new HashSet<ExercisesDependency>();
UserExercises = new HashSet<UserExercise>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<ExercisesDependency> ExerciseDependencyExercises { get; set; }
public virtual ICollection<ExercisesDependency> ExerciseDependencyTargetExercises { get; set; }
public virtual ICollection<UserExercise> UserExercises { get; set; }
}
public class UserExercise
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public long UserId { get; set; }
public long ExerciseId { get; set; }
}
public class ExercisesDependency
{
public long ExerciseId { get; set; }
public virtual Exercise Exercise { get; set; }
public long TargetExerciseId { get; set; }
public virtual Exercise TargetExercise { get; set; }
}
Easiest solution I can think of is to not have your requirements dictate primary keys values (which should only be used to uniquely identify a record).
I don't know/understand why you have this requirement. But I would suggest just continue numbering, and while creating the new records to calculate whether it should be an exercise of type 1, 2 or 3. e.g. 1=>1, 2=>2, 3=>3, 4=>1, 5=>2, 6=>3, 7=>1.
Then a simple: var type = ((id - 1) %3) + 1; returns that list of numbers.

Entity Framework Include with two foreign Keys

I have a Team table and a Matches table.
Team table:
Id Name
------------
1 TeamA
2 TeamB
If TeamA desires to play TeamB we will add a row in the Matches table
Matches table:
Id HomeTeamId RivalTeamId
-------------------------
1 1 2
If TeamB desires to challenge TeamA we will go about do the following
Matches table:
Id HomeTeamId RivalTeamId
-----------------------------
1 1 2
2 2 1
My Team and Match POCO (only relevant code) look like this:
public class Team : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Match> HomeMatches { get; set; }
public ICollection<Match> RivalMatches { get; set; }
}
public class Match : BaseEntity
{
public int Id { get; set; }
public string Description { get; set; }
//navs
public Team HomeTeam { get; set; }
public int HomeTeamId { get; set; }
public Team RivalTeam { get; set; }
public int RivalTeamId { get; set; }
}
Problem: I guess the experts can already notice a possibility of a cycle up there that I'll come across during query. My problem is that I would like to query TeamA's matches. I would do the following for that
Team team= dbContext.Team.
Include("HomeMatches").
In the above team object I notice that BOTH the properties HomeMatches and RivalMatches appear filled.
I would just want the HomeMatches properties filled. I am only interested in those matches which TeamA has chosen to play, not in those where TeamA is a rival.
My question is that when I am clearly mentioned Include("HomeMatches"), why is the RivalMatches property also filled?
You can try using Explicit loading as in here

Designing tables to avoid circular reference

Working in one project (Catering theme ) when I was designing the database I didn't take care about some thing , and now Is very hard to avoid some kine of errors(Circular error).
Suppose I have following scenario :
I have Meal object that should be composed from a list of semi-finished products (we will call it Product ) and list of simple Resources.
One Product is composed from a list of Resoruces and list of products.
So in real example this will look like this:
Meal: Pizza that contains list of Resoruces(cheese,dough) and list of Products : in our case will be just :Sauce.
Sauce will be composed from List of Resources(salt,Some cheese ,tomato Sauce) and a List of Products (in our case will be just one "Chopped tomatoes with salt")
So now I have following classes:
public class Resource
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ProductToProduct
{
public int Id { get; set; }
public Product MainProduct { get; set; }
public Product Component { get; set; }
public double Quantity { get; set; }
}
public class ProductToResource
{
public int Id { get; set; }
public Product Product { get; set; }
public Resource Resource { get; set; }
public double Quantityt { get; set; }
}
public class Meal
{
public int Id { get; set; }
public string Name { get; set; }
public IList<MealToProduct> MealToProducts { get; set; }
public IList<MealToResource> MealToResources { get; set; }
}
public class MealToResource
{
public int Id { get; set; }
public Meal Meal { get; set; }
public Resource Resource { get; set; }
public double Quantity { get; set; }
}
public class MealToProduct
{
public Meal Meal { get; set; }
public Product Product { get; set; }
public double Quantity { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public IList<ProductToResource> ProdcutToResources { get; set; }
public IList<ProductToResource> ProductToProducts { get; set; }
}
My problem is in relation between Product to Product.
Suppose I will have Product1, Product2 , Product3 , Product4.
Product 1 will be composed from something and Prodcut2, Product4.
Product2 will be composed from something and Prodcut3.
Prodcut 3 will be composed from something and Prodcut4.
Prodcut 4 will be composed from something and Prodcut1 , in this case when I will try to calcualte Cost for Product1 , or Product 4 I will get an Circular error.
So my problem is in ProductToProduct table.
My question is how I must to design tables to avoid this kind of errors .
I AM VERY SORRY FOR MY EXPLICATION BUT IT IS VERY HARD TO EXPLAIN THIS PROBLEM.
PLEASE ASK ME IF SOMETHING IS UNCLEAR.
THANKS FOR YOUR ATTENTION.
Note:This is not so important for this case but I am working in ASP.Net mvc , orm is Fluent Nhibernate.
Here's an example of a function you could use to detect whether a parent-child relationship exists. I have assumed that the product relationships are described in a table called ProductLink, which has two foreign keys to Product: ParentProductId and ChildProductId.
This function uses a recursive query to determine the complete list of products which are children of the product denoted by the argument #ParentProductId, then does a simple test to see whether #ChildProductId appears in that list.
create function dbo.ProductRelationshipExists
(
#ParentProductId int,
#ChildProductId int
)
returns bit
as
begin
declare #ChildExists bit = 0;
with ProductChildCTE as
(
-- Base case: Get the parent's direct children.
select ChildProductId from ProductLink where ParentProductId = #ParentProductId
-- Recursive case: Get the children's children.
union all
select
ProductLink.ChildProductId
from
ProductChildCTE
inner join ProductLink on ProductChildCTE.ChildProductId = ProductLink.ParentProductId
)
select #ChildExists = 1 from ProductChildCTE where ChildProductId = #ChildProductId;
return #ChildExists;
end
When someone tries to insert a record into ProductLink, you could use a test like this to determine whether the proposed parent and child are already in the table as child and parent, respectively, and disallow the insertion if so.
This was just a quick write-up to illustrate one possible approach; I should mention that I don't know how well the performance of this thing will scale as the table gets larger. Hopefully it will suffice for your case. If not, let me know how to improve it.

Categories