How to prevent creating relations by EntityFramework Core - c#

I am making a school project which is a shop.
I have created a Product class:
public Guid Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public string PhotoUrl { get; set; }
public int Quantity { get; set; }
and an Order class:
public Guid Id { get; set; }
public List<Product> Products { get; set; }
public decimal TotalPrice { get; set; }
//address
public string Street { get; set; }
public string HouseNumber { get; set; }
public string PostCode { get; set; }
public string City { get; set; }
public Order()
{
Products = new List<Product>();
}
As you see in Order.cs there is a list of Products, but entity framework always sets a relationship between my product and a order but I just want to add a Product to this list with no relation ship.
As a response I want to get something like this
{
"id" :"someID",
"products": [
{
first product
},
{
second product
}]
}
etc. How can I prevent creating by ef relationships and do simple lists?
Or how can I do a relationship many products to many orders?

You can add the NotMapped attribute to the Property:
...
[NotMapped]
public List<Product> Products { get; set; }
...
You will need to import System.ComponentModel.DataAnnotations

Either I'm missing something, or you are trying to do something that doesn't make much sense. You say there is no relation - but you do want to save both Order and it's Products to the database? That means that there IS relation (of 1:N kind) and EF is right to create it. It can't work without it.
You didn't include full output that you expect, only the Order part with first_product and second_product placeholders. If the placeholders look like your Product class, just let EF create the relation and you are done. If you want them to look different in JSON (omit some properties for example), you should still let EF create the relation, and then write transformation from your Entity classes (Product, Order) to DTO classes (ProductDTO, and OrderDTO that has List<ProductDto>). Which is good practice anyway, even if Entity and DTO match 1:1, in real project it rarely stays that way for long.

Related

Looking way to create a relationship between entities

I have two entities one is employee and other one is project and i am looking to store the list of all bookmarked project ID's in employee entity and one employee can add bookmarks to multiple projects. One project can be bookmarked by multiple employees as well.
The employee entity structure is like this
public class Employee
{
[Key]
public int Id { get; set; }
public string Email { get; set; }
public string DisplayName { get; set; }
public List<Section> OwnedSections { get; set; } = new List<Section>();
public List<string> BookmarkProjectsIDs { get; set; } // just specified the list of bookmark projectID's
}
and the below is the project entity structure
public class Project
{
[Key, GraphQLNonNullType]
public string ProjectNumber { get; set; }
public string Name { get; set; }
[Column(TypeName = "jsonb")]
public ProjectSectionStatus SectionStatuses { get; set; } = new ProjectSectionStatus();
}
Is this is right way to specify or is there any way we can specify just to store the ID's of projects and at the same time i do not want to duplicate the data as well. I am using Entity framework core with .Net core.
many thanks in advance.

Entity framework: Unable to define 1:1 relationship

I'd like to define relationship where Student can have only one favorite Course. I expect it would look like this in DB:
STUDENT
ID
Name
FavoriteCourseID
COURSE
ID
Name
How to achieve this with entity framework? I'd prefer to specify it just by attributes. I tried:
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public Course FavoriteCourse { get; set; }
public int? FavoriteCourseID { get; set; }
}
public class Class
{
public int ID { get; set; }
public string Name { get; set; }
}
which gave me this DB model:
STUDENT
ID
Name
FavoriteCourseID
COURSE
ID
Name
StudentID // how to remove this?
Note, that it may happen that several students have the same favorite class and therefore this is unacceptable solution.
Another question: what type of relationship this is? (1:1 / 1:N ?)
To specify 1 to 1 relationship, it is assumed, that primary key for the related entity matches the primary key of first entity. Also you should specify a virtual property to related entity:
public class Student
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public Course FavoriteCourse { get; set; }
public int? FavoriteCourseID { get; set; }
}
public class Class
{
[Key]
[ForeignKey("Student")]
public int ID { get; set; }
public string Name { get; set; }
public virtual Student Student { get; set; }
}
And it will be one-to-zero-or-one relationship. Check this tutorial.
If you will mark FavouriteCourse property with RequiredAttribute, it seems, that it will result in strong one to one relationship.
It will result in adequate database structure:
STUDENT
ID
Name
FavoriteCourseID
COURSE
ID
Name
However, if many students could have one favourite course, this structure will be a problem, as you want one-to-many instead of one-to-one. And you will have a duplicate records in database, because one course can refer only to one student. You have to think about your db design.
You can try this:
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
[ForeignKey("FavoriteCourseId")]
public Course FavoriteCourse { get; set; }
public int? FavoriteCourseId { get; set; }
}
Normally, you define one of the following relations:
Optional:Optional
Required:Optional
Optional:Many
Required:Many
Many:Many
Having Required:Required is not a usual relation, inserting the first entry with such a relation needs special treatment.
I Suppose you want Required:Many as in "Each student has one favorite course but many students may chose the same favorite course".

Multiple Many-to-Many relationsship Entity Framework

The main goal is the ability to have a many to many relationship between the table Mucle and Exercise. I want an Exercise to have both a primary and a secodary muscle group.
Is it possible to have two icollections in one model and only one in the other?
If someone could help with the "fluent configuration" as well, I would appreciate it!
Here is the code I have got right now.
public class Muscle
{
public int MuscleID { get; set; }
public bool IsFront { get; set; }
public string Name { get; set; }
public virtual ICollection<Exercise> Exercises { get; set; }
}
public class Exercise
{
public int ExerciseID { get; set; }
// ExerciseCategory
public int ExerciseCategoryID { get; set; }
public DateTime CreationDate { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public virtual ExerciseCategory ExerciseCategory { get; set; }
public virtual ICollection<Muscle> Muscles { get; set; }
public virtual ICollection<Muscle> MusclesSecondary { get; set; }
}
No way to map the model you described.
To map your model (2 n-m relationship) you would need a Junction table with a discriminator and you can't do it with EF.
You have several way to change your model to make it work with EF
You create a model (a class) for the Junction table and insert a discriminator in it. Your model changes (and I think that the new model is less clear)
Why is there a Muscles and MusclesSecondary? Can it be discriminated with an attribute of Muscle? In this case you can have the attribute in Muscle and remove Exercise.MusclesSecondary Then you have only an n-m relationship that EF handles with a Junction table.
If you want this model you can add 2 collections to Muscle (for example ExcercisesMuscle and ExercisesMusclesSecondary) and a 3rd not mapped collection where you have the content of ExcercisesMuscle and ExercisesMusclesSecondary toghether. About the ExcercisesMuscle and ExercisesMusclesSecondary they can be observable collections so you can cache the content of Exercises collection in an efficient way.

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.

EF Code first - Lazy Loading How to set up and access the joining table

public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public bool IsInStock { get; set; }
public string ImageUrl { get; set; }
public List<ProductOption> ProductOptions { get; set; }
public virtual Category Category { get; set; }
}
public class ProductOption
{
[Key]
public int Id { get; set; }
public string ProductOptionName { get; set; }
public string ProductOptionDescription { get; set; }
}
Now I know when your using Code First EF, so that the tables are created correctly. You need to do something like this.
modelBuilder.Entity<Product>().HasMany(p => p.ProductOptions).WithMany().Map(m =>
{
m.MapLeftKey("ProductId").MapRightKey("ProductOptionId").ToTable("SelectedProductOptionsInOrderedItem");
});
So....
Does this mean that if I do something like Product.ProductOptions I will be able to access all associated productoptions.
Is this the best way to set it up, or is there another way?
To enable lazy load and EF can create derived proxy types for your collection, that property should be declared this way:
public virtual ICollection<ProductOptions> ProductOptions { get; set; }
That should be enought. Other aspect is the mapping approach that you use. You choose fluent api, i prefer mapping by convention, but that is a matter of personal taste anyway.
Ok, Mapping by Conventions:
Is the ability of EF that from the name of entities and their properties along with their types, to map our model with the underlying data without providing any other information.
for example
public class Customer {
public long CustomerID {get; September;}
public string CustomerName {get; September;}
public Employee AssignedTo {get; September;}
}
With the previous model EF will map database with a table named Customer with:
. CustomerID bigint primary key column
. CustomerName nvarchar column
. Customer_EmployeeID foreign key to Employee table, with the datatype Corresponding to EmployeeID in that table.
You can read more Here

Categories