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

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!

Related

How can I insert Billing Information after Providing Patient Diagnosis Information in one-to-one relationship One after another

The Application I am trying to make is Hospital Management System. In the EnterPatientDiagnosis Form(screenshot is given at the end), I need to Add The Patient's Diagnosis Information 1st then I need to Add its associated Billing Information. Here,Both of tables Primary Key Column is an Identity Column.
This is a common step in many Systems .But I still couldn't find details on how to achieve it.
One solution I thought of is to insert all the Diagnosis Information keeping the FK_billId attribute Null using Stored Procedure and get the DiagnosisId as output parameter form the Stored Procedure. Then when user will Submit Bill information I will use the BillId and DiagnosisId to update the previously inserted row in the Diagnosis Table. But I do not like this approach for 2 reason:
Firstly, Because it has an extra update query. Since, If I used the DiagnosisId as a foreign key between this 2 Database Tables rather than BillId then there would not be any need for this update query. But I haven't found anywhere giving any rules/precedence on which Key you should use as FK in One-to-One relation.
Secondly, It conflicts with the Entity Class that I have created. I have manually created 2 classes for this 2 tables in my Entity Layer. So, If I want to insert row through entity layer then I would have to give The Billing class a new Property named DiagnosisId which is contradictory with my Database Table Schema.
Here is the 2 classes in Entity Layer:
public class EntityPatientDiagnosis
{
//Diagnosis Id is automatically assigned
public int DiagnosisId { get; set; }
public int PatientId { get; set; }
public string Symptoms { get; set; }
public string DiagnosisProvided { get; set;}
public string AdministeredBy { get; set; }
public DateTime DateofDiagnosis { get; set; }
public string FollowUpRequired { get; set; }
public DateTime DateOfFollowUp { get; set; }
public int BillId { get; set; } //BillId -> Foreign Key
}
public class EntityBilling
{
//BillId -> Primary Key ->set automatically
public int BillId { get; set; }
public int BillAmount { get; set; }
public string CardNumber { get; set; }
public string ModeOfPayment { get; set; }
}
Here is the picture of the ERD of the tables and Web Forms:
You can try a different approach. You can change the relationship between entities PatientDiagnosis and Billing. So, at first you can create a PatientDiagnosis entry and then create a Billing entry for it.
public class EntityPatientDiagnosis
{
//Diagnosis Id is automatically assigned
public int DiagnosisId { get; set; }
public int PatientId { get; set; }
public string Symptoms { get; set; }
public string DiagnosisProvided { get; set;}
public string AdministeredBy { get; set; }
public DateTime DateofDiagnosis { get; set; }
public string FollowUpRequired { get; set; }
public DateTime DateOfFollowUp { get; set; }
}
public class EntityBilling
{
//BillId -> Primary Key ->set automatically
public int BillId { get; set; }
//DiagnosisId -> Foreign Key unique
public int DiagnosisId { get; set; }
public int BillAmount { get; set; }
public string CardNumber { get; set; }
public string ModeOfPayment { get; set; }
}

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".

Creating new table with foreign key with Entity Framework Core

I have a DbContext which I via the developer command prompt and creating a migrations schema turn in to my database. But if you look at the product object I have a dictionary object named Parts. That property does not get added to the Product table when the database is updated in the command prompt. I don't even know if it is possible what I am trying to do.
I want to add a table in the database named Parts and then add a foreign key to the Product table which connects the Parts dictionary object in the Product table, and the the new Parts table. Is this possible with Entity Framework Core?
public class ShoppingDbContext : IdentityDbContext<User>
{
public ShoppingDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
}
public DbSet<Product> Products { get; set; }
public DbSet<Order> Orders { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public double Price { get; set; }
public int CategoryId { get; set; }
Dictionary<string, Part> Parts { get; set; }
}
EF Core can't currently map a dictionary property directly. If you want to create an association between Products and Parts, then define each of them as an entity. You can then create navigation properties between them--a reference from Part to the Product which it belongs, and a collection of Parts on Product. For example:
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public double Price { get; set; }
public int CategoryId { get; set; }
public ICollection<Part> Parts { get; set; }
}
public class Part
{
public int PartId { get; set; }
public int ProductId { get; set; }
public Product Product { get; set;}
}
Part also defines a property ProductId that acts as the FK to the Product entity. You don't need to add that property--EF will simulate it for you if you don't want it, but usually it is easier to deal with entities if the FK is mapped to a property.
Relationships are tracked through object references instead of foreign key properties. This type of association is called an independent association.
More Details Here:
https://msdn.microsoft.com/en-us/data/jj713564.aspx
Sample code:
public partial class Product
{
public Product()
{
this.Parts = new HashSet<Part>();
}
public int ProductId { get; set; }
public string ProductName { get; set; }
public double Price { get; set; }
public int CategoryId { get; set; }
public virtual ICollection<Part> Parts { get; set; }
}
Basically like what Arthur said, EF Core does not support it yet.
However, another way is to create a composite table should you want to or if it's viable for your use.
Here's a simple example:
// -------------- Defining BrandsOfCategories Entity --------------- //
modelBuilder.Entity<BrandCategory>()
.HasKey(input => new { input.BrandId, input.CatId })
.HasName("BrandsOfCategories_CompositeKey");
modelBuilder.Entity<BrandCategory>()
.Property(input => input.DeletedAt)
.IsRequired(false);
// -------------- Defining BrandsOfCategories Entity --------------- //
public class BrandCategory
{
public int CatId { get; set; }
public int BrandId { get; set; }
public DateTime? DeletedAt { get; set; }
public Category Category { get; set; }
public Brands Brand { get; set; }
}
The DeletedAt is optional of course. This handles M-M Relationships.
I had the same issue, I resolved it by removing the keyword virtual on the navigation properties and with in the ApplicatinDbContext

Creating many to many junction table in Entity Framework

I am trying to add a many to many relationship between two of my entities. I need a junction table with an additional field, I'm aware that means EF cannot do this automatically and that I need to create an Entity for my junction table.
I have the following models
public class Supplier
{
public int Id { get; set;}
public virtual ICollection<SupplierUsers> UserPermissions { get; set; }
}
And
public class User
{
public string Id { get; set;}
public virtual ICollection<SupplierUsers> UserPermissions { get; set; }
}
I need for a user to have a permission stored in the junction table. So I have created the following entity
public class SupplierUsers
{
public string UserId { get; set; }
public int SupplierId { get; set; }
public SupplierUserPermission Permission { get; set; }
public virtual Supplier Supplier { get; set; }
public virtual User User { get; set; }
}
In my OnModelCreating I've also added the following (this is probably where I'm going wrong)
modelBuilder.Entity<SupplierUsers>()
.HasKey(x => new { x.UserId, x.SupplierId });
This works to an extent, I can successfully add a user/supplier/permission to this table.
But I cannot add the same user / supplier multiple times to this table (probably due to the PK?).
How can I alter my code so that I can add the same user or supplier multiple times in this table?
Here's what the table structure looks like at the moment:
Thank you.
If i understand you correctly you want to add multiple equal pairs of UserId and SupplierId to SupplierUsers, right?
Add a SupplierUsersId field to your SupplierUsers entity and make it primary key.
public class SupplierUsers
{
public int SupplierUsersId { get;set; }
public string UserId { get; set; }
public int SupplierId { get; set; }
public SupplierUserPermission Permission { get; set; }
public virtual Supplier Supplier { get; set; }
public virtual User User { get; set; }
}
Remove the configuration from OnModelCreating()

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