Cannot insert duplicate key. Composite Primary key. ASP.NET Entity Framework - asp.net

I'm trying to create application using Entity Framework.
There's what I want to do (every entity has Id as well):
I want to use composite primary key in this case (PatientId + DiagnosisId).
There's a collection of Diagnoses in Patient model class:
public ICollection<Diagnosis> Diagnoses { get; set; }
public class Diagnosis
{
[Required]
[MaxLength(200)]
public String Type { get; set; }
public String Complications { get; set; }
public String Details { get; set; }
public Int32 DiagnosisId { get; set; }
public Patient Patient { get; set; }
public Int32 PatientId { get; set; }
}
Also in the database context I defined
public DbSet<Diagnosis> Diagnoses { get; set; }
and
modelBuilder.Entity<Diagnosis>().HasKey(x => new { x.DiagnosisId, x.PatientId });
in OnModelCreating method to create the composite primary key.
In an ASP.NET MVC CRUD controller I create Diagnosis and every time DiagnosisId is the same = 0. And I can't paste new data to database because it's like duplicate. That's my create post method on Pastebin if it could help

The parent key goes first:
modelBuilder.Entity<Diagnosis>().HasKey(x => new { x.PatientId, x.DiagnosisId });
Because you want all the Diagnoses for a particular Patent to be stored together.
And you need to request that the key is generated by the database. For EF Core its:
modelBuilder.Entity<Diagnosis>().Property(r => r.DiagnosisId).ValueGeneratedOnAdd();
for EF6 it's:
modelBuilder.Entity<Diagnosis>().Property(r => r.DiagnosisId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

Related

Entity Framework Core - optional foreign key

I am creating a web api that needs to return details about vehicles. The first part works fine, just returning data from my vehicles table. Now I have another table which may or may not contain additional data about vehicles in the first table. So when I get vehicle data, I want all of the vehicle data, and any additional data from the second table if it exists, like a left join in SQL.
Here are my classes (very much abridged for readability):
public class Vehicle
{
[Key]
[Required]
public string registrationNo { get; set; }
public string capacity{ get; set; }
public string maxGross{ get; set; }
}
public class VehicleDvlaDetail
{
[ForeignKey("Vehicle")]
public string? registrationNumber { get; set; }
public int? co2Emissions { get; set; }
}
And in my context class OnModelCreating I have (again, very abridged):
modelBuilder.Entity<Vehicle>(entity =>
{
entity.HasOne(dvlaRec => dvlaRec.dvlaDetail).WithMany().HasForeignKey(dvla => dvla.registrationNo);
});
This works fine when there is an associated record in the DVLA table, but that isn't always the case. I need to keep them as separate entities as my API will be required to return details from the DVLA table separately as well. Is there any way to create an optional foreign key, as clearly, what I am doing is wrong.
Friendly advice:
Primary key as a string is not a good practice because of performance issues when data table has lots of data in it.
It would be better if you create your model like this:
public class Vehicle
{
public long Id { get; set; }
public string RegistrationNo { get; set; }
public string Capacity { get; set; }
public string MaxGross { get; set; }
public List<VehicleDvlaDetail> VehicleDvlaDetails { get; set; }
}
public class VehicleDvlaDetail
{
public long? VehicleId { get; set; }
public int? Co2Emissions { get; set; }
public Vehicle Vehicle { get; set; }
}
Vehicle and VehicleDvlaDetail are now connected without additional code in OnModelCreating method and it is possible to fetch vehicles with details like this (this is assuming you have named properties in dbcontext Vehicles and VehicleDvlaDetails):
_dbContext.Vehicles.Include(x => x.VehicleDvlaDetails).ToList();
Also as foreign key VehicleId is nullable - this allows for vehicles not to have any dvla details.
Wow. I spent about 3 hours looking for the answer, just posted the question and came across this:
Create an optional foreign key using the fluid-API for Entity Framework 7
So simple...

Using the same generic foreign key field (KeyId) along with a (Type) field for a single table in EntityFramework

I have a class called Address with the following properties:
public int Id { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public int KeyId { get; set; }
public AddressType Type { get; set; }
The plan is for AddressType to be an enum of either: Customer, Vendor, or Location and the KeyId to be the Foreign Key from either the Customer, Vendor, or Location.
Is this something that can be done correctly with Entity Framework or should I be making 3 separate classes CustomerAddress, VendorAddress, LocationAddress.
You need to generate an entity inheritance structure from a single database table. Can achieve that by using a Table per Type approach
TBT Entity Framework
Group the common properties into a "Base" entity, and then use a discriminator (in your case the AddressType) for specializing the object.
I looks like you have three tables Customer, Vendor, or Location and you want to save Address for each.
Then instead of adding AddressType in Address table, you should include AddressID in each table as Foreign key and must have a Address navigation property in each table.

Wrong navigation properties when using SQLite and Entity Framework 6

Lately I've been playing around with SQLite using Entity Framework but something is not very clear to me regarding the navigation properties of the generated entities after DB first approach. And more specifically, many-to-many relationships.
Note: Using ASP.NET Web Api OWIN project.
This is what I did:
I installed latest version of Entity Framework
I installed latest version of System.Data.SQLite
I used Firefox add-on to create my database. It generated my *.sqlite
Example for one of my many-to-many db definitions while creating the DB:
CREATE TABLE "Users"
(
"Id" INTEGER PRIMARY KEY NOT NULL UNIQUE ,
"IdSrvId" INTEGER NOT NULL UNIQUE ,
"FirstName" VARCHAR NOT NULL ,
"LastName" VARCHAR NOT NULL ,
"Email" VARCHAR NOT NULL ,
"About" VARCHAR NOT NULL ,
"GenderId" INTEGER NOT NULL UNIQUE ,
"BirthDate" DATETIME,
"PhoneNumber" VARCHAR
)
CREATE TABLE "UserLanguаges"
(
"Id" INTEGER PRIMARY KEY NOT NULL UNIQUE ,
"UserId" INTEGER NULL REFERENCES Users(Id),
"LanguageId" INTEGER NULL REFERENCES Languаges(Id)
)
CREATE TABLE "Langugaes"
(
"Id" INTEGER PRIMARY KEY NOT NULL UNIQUE ,
"Name" VARCHAR NOT NULL UNIQUE
)
After that, I used Visual Studio 2015 to create a Data Model using that *.sqlite file. Following this tutorial: SQLite EntityFramework 6 Tutorial
After the generation I got all of my tables as entities looking like this:
public partial class User
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public User()
{
this.GroupUsers = new HashSet<GroupUser>();
this.UserLanguаges = new HashSet<UserLanguаges>();
}
public long Id { get; set; }
public long IdSrvId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string About { get; set; }
public long GenderId { get; set; }
public Nullable<System.DateTime> BirthDate { get; set; }
public string PhoneNumber { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserLanguаges> UserLanguаges { get; set; }
}
public partial class Languаges
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Languаges()
{
this.UserLanguаges = new HashSet<UserLanguаges>();
}
public long Id { get; set; }
public string Name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserLanguаges> UserLanguаges { get; set; }
}
public partial class UserLanguаges
{
public long Id { get; set; }
public Nullable<long> UserId { get; set; }
public Nullable<long> LanguageId { get; set; }
public virtual Languаges Languаges { get; set; }
public virtual User User { get; set; }
}
What worries me here, are the navigation properties inside User and Language entities. As you can see, they make a reference to the 'bridge' table helping for the many-to-many relationship but not directly to the other entity as I expected.
I expected this:
public virtual ICollection<UserLanguаges> UserLanguаges { get; set; }
to look like this:
public virtual ICollection<Languаge> Languаges { get; set; }
inside of the User entity.
How can I fix that?
The only time Entity Framework can omit the join table is if that table consists purely of the keys of the tables being joined in a many-to-many relationship. It's the presence of the Id column on this table that is causing it to generate a new entity.
The only way around this is to remove that Id column and make that table have a composite key consisting of the UserId and LanguageId keys. If you cannot change the database schema, there's no other option but take a deep breath and accept how it works.
Some additional reading on how EF handles many-to-many relationships: https://msdn.microsoft.com/en-us/library/dd742359.aspx

Entity Framework: how to implement shared primary key with Fluent API?

I have two tables and want to use PK of one of them in another one as PK.
This is my implementation with data annotation:
public class User
{
public System.Guid UserId { get; set; }
public string UserName { get; set; }
}
public class Student
{
[Key, ForeignKey("User")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public System.Guid StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// shared primary key
public virtual User User { get; set; }
}
Here Student table uses User's primary key.
How can I implement this with Fluent API?
(As a second question, if I delete a value from Student table, will accur a cascade delete?)
How can I implement this with Fluent API?
modelBuilder.Entity<Student>()
.HasRequired(s => s.User)
.WithOptional();
if I delete a value from Student table, will accur a cascade delete.
No, because Student is the dependent in the relationship (it carries the foreign key) and not the principal (which is User). Cascading delete is only in effect if you delete the principal. For a one-to-one relationship you have to enable it manually though:
modelBuilder.Entity<Student>()
.HasRequired(s => s.User)
.WithOptional()
.WillCascadeOnDelete(true);
Now, if a User gets deleted the related Student (if there is any) will be deleted as well.

ASP.NET MVC 3 EntityType has no key defined

I want to display customer information.
Then I created some classes; Customer, Delivery, Order, OrderLine, Product, and rentalDB.
rentalDB class sets 5 DbSet of Product, Customer, Order, OrderLine, and Delivery.
When I make UserController with list view, I cannot display the customer information, and it takes errors:
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'OrderLine' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntityType: : EntityType 'Delivery' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �OrderLine� is based on type �OrderLine� that has no keys defined.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �Delivery� is based on type �Delivery� that has no keys defined.
I don't know why these entities require key?
I have no idea for this error..
Could you help me?
--UserController.cs--
namespace MvcApplication2.Controllers
{
public class UserController : Controller
{
//
// GET: /User/
rentalDB _db = new rentalDB();
public ActionResult Index()
{
var model = _db.Customer;
return View(model);
}
}
}
--Delivery.cs in Models folder--
namespace MvcApplication2.Models
{
public class Delivery
{
public int trackId { get; set; }
public String address { get; set; }
public String postCode { get; set; }
public decimal deliveryPrice { get; set; }
public DateTime deliveryDate { get; set; }
public DateTime returnDate { get; set; }
}
}
--OrderLine.cs in Models folder--
namespace MvcApplication2.Models
{
public class OrderLine
{
public int basketId { get; set; }
public int productId { get; set; }
public int quantity { get; set; }
}
}
In order to use the entity framework, every entity needs a key. This is how EF tracks objects in its cache, posts updates back to the underlying data store, and links related objects together.
Yours objects already have keys, you just need to tell the EF about them:
namespace MvcApplication2.Models
{
public class Delivery
{
[Key] public int trackId { get; set; }
public String address { get; set; }
public String postCode { get; set; }
public decimal deliveryPrice { get; set; }
public DateTime deliveryDate { get; set; }
public DateTime returnDate { get; set; }
}
}
When you use an ORM (object-relational mapper) framework like NHibernate or Entity framework that helps you map a relational database to an object model you need something that will let you make a meaningful relation between your objects in memory and rows of data in your database and that thing is a key (id as NHibernate call it) and usually that's the natural way that RDBMS track records using a Primary key (usually you use DB primary key as the key of your object)
When you check to see if two objects are equal using == operator you are checking that those objects have the same reference (or address in memory). This kind of equality is not very helpful when you are using an ORM .You can load multiple instances of a record in memory with different references so that it's impossible to check the equality of objects by their references .That's when checking equality by value come into play and keys have the main role in this play.

Resources