Wrong navigation properties when using SQLite and Entity Framework 6 - sqlite

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

Related

Foreign key created in shadow and appending random 1 to column name ASP:NET EF Core

When I migrate my new models and data I get the following error for multiple foreign keys:
The foreign key property 'FavoriteList.SongId1' was created in shadow
state because a conflicting property with the simple name 'SongId'
exists in the entity type, but is either not mapped, is already used
for another relationship, or is incompatible with the associated
primary key type. See https://aka.ms/efcore-relationships for
information on mapping relationships in EF Core.
Example of my models:
public class FavoriteList
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int MovieId { get; set; }
[ForeignKey("MovieId")]
public int SongId { get; set; }
[ForeignKey("SongId")]
public int CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Movie Movie { get; set; }
public virtual Song Song { get; set; }
public virtual Customer Customer { get; set; }
}

Cannot insert duplicate key. Composite Primary key. ASP.NET Entity Framework

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);

.Net Core Foreign Key Field always null

We have a .net core api project. Foreign Keyed model always returning null from select queries.
DBContext is initialized with UseLazyLoadingProxies option.
Foreign key relation is defined in the table ContentTopic.
Foreign key is defined as ContentTopic->TopicId = Topic->Id
In the sample below Topic always return null.
services.AddDbContext<VaultContext>(options =>options.UseLazyLoadingProxies().UseSqlServer(Configuration.GetConnectionString("DBContext")));
[Table("ContentTopic")]
public class ContentTopic
{
[Key]
public long Id { get; set; }
public long TopicId { get; set; }
public long ContentId { get; set; }
public DateTime CreateDate { get; set; }
public bool IsInBody { get; set; }
[ForeignKey("TopicId")]
public virtual Topic Topic { get; set; }
}
UseLazyLoadingProxies extension must be called from DBContext in OnConfiguring method not from Startup.cs

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.

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