Code first from database doesn't create the primary key in the builder of the dbContext - ef-code-first

I have a Sqlite database and I have installed Sqlite v1.0.99.0. To create my connection, I am using code first from database, but in the dbContext, in the method when it is used fluent to set the relationships between the entities, the primary key is not set, so I get an error when I try to run my application.
Is there any way that the primary key is set using code first from database to avoid to have to set the primary key in the entities?
Thanks.

Alas you forgot to show the class that describes your entity nor the DbContext that contains this class.
A good beginner's description can be found in "A beginner's guide to entity framework code first"
Here you can see that if you follow certain conventions you don't have to explicitly define the primary key. Entity framework does this for you.
Quite often you see the example of a database with blogs, where each blog has zero or more posts. The blog and the post will have an Id which is the primary key and the post has a foreign key to the Id of the blog.
If you don't want to specify the properties that contains the primary key, nor the ones that contain the foreign keys, define your classes as follows:
public class Blog
{
public int Id {get; set;}
public virtual ICollection<Post> Posts {get; set;}
...
}
public class Post
{
public int Id {get; set;}
public int BlogId {get; set;}
public virtual Blog Blog {get; set;}
...
}
public class MyDbContext : DbContext
{
public virtual DbSet<Blog> Blogs {get; set;}
public virtual DbSet<Post> Posts {get; set;}
}
In the code above, property Id will automatically be the primary key of Blog and Post entities. If desired you can decide to use property names Blog.BlogId and Post.PostId. Personally I don't prefer this because this would mean that all my primary keys have different identifiers.
Property Post.BlogId will automatically be the foreign key of the blog the post belongs to.

Related

Entity Framework swaps navigational properties

I am using EF with DB first approach. I am facing an issue while updating the EDMX file. Suppose I have a table InvoiceT and another table LookupT. Now, in InvoiceT I have a column InvoiceType having FK relation with LookupT. Now entity creates a navigational property in InvoiceT class with the name LookupT. So far, its good.
Now I added another column with name InvoiceStatus and FK with LookupT. Now entity creates another navigational property with the name LookupT1. But the issue here is that first navigational property LookupT is not pointing to its original data i.e. InvoiceType. Instead, its pointing to InvoiceStatus data now. Can anybody please explain to me why its behaving like this and what can I do about it?
public class InvoiceT
{
public int InvoiceId {get;set;}
public int InvoiceStatusLkpId {get;set;}
public int InvoiceTypeLkpId {get;set;}
public virtual LookupT LookupT {get;set;} // Previously pointing to Type. Now to Status.
public virtual LookupT LookupT1 {get;set;} // Pointing to Type
}
public class LookupT
{
public int LookupId {get;set;}
public string LookupValue {get;set}
public virtual ICollection<InvoiceT> InvoiceT {get;set;}
public virtual ICollection<InvoiceT> InvoiceT1 {get;set;}
}
So I figured out the issue. Seems like when EF creates the navigational properties, it does this in order of FK relation names i.e. if I have two FK relations with name RelationA and RelationB, then the navigational property for RelationA will be created first and then for RelationB. In my scenario, the relation names for my type and status were 'FK_InvoiceT_LookupT_InvoiceTypeLkpId' and 'FK_InvoiceT_LookupT_InvoiceStatusLkpId' (which SQL designer generates automatically) respectively and EF first generated the navigational property for the relation that was added later and it messed up my ordering. So all I had to do was to update relation names in order in which they were added and everything started working fine.

Entity Framework making incorrect PK-FK mapping on Code First migration

I have the following 3 classes set up to be created in a SQL Server database using Entity Framework Code First migrations. The Survey object is the main table.
public class Survey
{
public int SurveyId {get; set;} //Primary Key
public string Description {get; set;}
public bool HasDevice {get; set;}
public bool HasProcess {get; set;}
public virtual Process Process {get; set;}
public virtual ICollection<Device> Devices {get; set;}
}
Each Survey can have multiple Devices (1-to-many)
public class Device
{
public int DeviceId {get; set;} //Primary Key
public string DeviceType {get; set;}
public int SurveyId {get; set;} //Foreign Key
public virtual Survey Survey {get; set;}
}
Each Survey should have only one Process (1-to-0..1)
public class Process
{
public int ProcessId {get; set;} //Primary Key
public string ProcessInfo {get; set;}
public int SurveyId {get; set;} //Foreign Key
public virtual Survey Survey {get; set;}
}
The Fluent API mapping for these classes looks like this.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("Survey");
modelBuilder.Entity<Survey>().HasOptional(x => x.Process).WithRequired(x => x.Survey);
modelBuilder.Entity<Survey>().HasMany(x => x.Devices).WithRequired(x => x.Survey);
}
The problem is that when I apply the code first migration, the ForeignKey property in the Process table (1-to-0..1) keeps getting set to the ProcessId field rather than the SurveyId. This means that every time I try to add a new Process record, I get the following error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Survey.Processes_Survey.Surveys_ProcessId". The conflict occurred in database "Backflow", table "Survey.Surveys", column 'SurveyId'.
The 1-to-many mapping for Device works just fine.
I thought initially that this was due to having all my PK fields just say Id, but even after adding in the additional label part, it still makes the incorrect PK-FK link. I have also tried avoiding the Fluent API by adding the DataAnnotation [Key, ForeignKey("xyz")] instead but it has the same result. Recompiling the project, restarting Visual Studio, and even creating a new project and a new database do not help.
Is there something in the Fluent API or DataAnnotations that I am missing to get this to join correctly? Also, manually fixing the FK in the database does make it work, but that kind of defeats the purpose of doing everything in Code First with migrations.
The fluent mapping of the 1-0..1 relationship is correct:
modelBuilder.Entity<Survey>()
.HasOptional(s => s.Process)
.WithRequired(p => p.Survey);
But Process shouldn't have a SurveyID property (and column). In EF6, the dependent part of a 1-0..1 relationship (here: Process) is supposed to have a primary key that also refers to its principal (here: Survey) as foreign key. So Process.ProcessID is both primary key and foreign key. Thus, one Process is uniquely tied to one Survey.
By the way, in the other mapping, I would also mention the foreign key: if configuration is chosen over convention, it better be complete.
modelBuilder.Entity<Survey>()
.HasMany(s => s.Devices)
.WithRequired(d => d.Survey)
.HasForeignKey(d => d.SurveyId);

Updating related entities in an ASP.NET MVC application using Entity Framework

Let's say I have two classes, a Company class and a Customer class.
public class Company
{
public int Id {get; set;}
public Customer Customer {get; set;}
}
public class Customer
{
public int Id {get; set;}
public string Name {get; set;}
}
I want to be able to update the customer associated with the company using a drop down list. So, the edit method in my controller creates a viewmodel.
public class ViewModel
{
public List<Customer> AvailableCustomers {get; set;}
public Company Company {get; set;}
}
The view creates a form with a drop down list from which to select a customer (using Knockout).
<select data-bind="attr: {name: 'Company.Customer.Id'}, options: AvailableCustomers(), optionsText: 'Name', optionsValue: 'Id', value: Company.Customer.Id"></select>
When the form is posted back to the server, I have the Company model with the new Customer Id selected by the user. Now I want to update the database using Entity Framework.
I get the Company being updated out of the database using the id for the Company that was posted back in the form data, which is just my viewmodel from earlier. Now I want to update the Company with a new Customer. The only information I have at this point is the Id of the Company that the user selected from the drop down list. So I do something like this:
var companyBeingUpdated = repository.GetByKey<Company>(Company.Id);
companyBeingUpdated.Customer.Id = Company.Customer.Id;
As soon as I call update on my repository, I get an exception that says "The property 'Id' is part of the object's key information and cannot be modified". The update method on my repository looks like this:
public void Update<TEntity>(TEntity entity) where TEntity : class
{
var entry = this._dbContext.Entry(entity);
if (entry.State == EntityState.Detached)
{
this._dbContext.Set<TEntity>().Attach(entity);
}
entry.State = EntityState.Modified;
}
I am clearly doing something wrong with Entity Framework. I could easily do this with a SQL statement, but I want to understand what I am doing wrong with EF.
How do I go about updating the Customer related entity of the Company object with EF when the only information I have is the Customer Id posted back in the form data?
I know I could probably retrieve the Customer entity from the database using the Id and assign the Company.Customer to that retrieved Customer, but this is actually a very simplified example. In reality, I have quite a bit more than just one related entity and if I have to make a trip to the database to look up each related entity in order to do the update, I can see performance quickly becoming a problem.
What you want to do with your entities is have access to the Foreign Key. however, you cannot directly access the Foreign Key through the related entity, instead you are accessing the Primary Key of that related entity.
i.e. instead of accessing the Company Customer_Id property in SQL, you are accessing the Customer Id property.
You can expose the Foreign Keys to your model in Entity Framework, allowing you to do the types of updates you are after.
public class Company
{
public int Id {get; set;}
[ForeignKey("CustomerId")]
public Customer Customer {get; set;}
public int CustomerId {get;set;}
}
now, you can do updates as companyBeingUpdated.CustomerId = Company.CustomerId; and not have to do a lookup to retrieve the full Customer Entity.

One To One Relationship With EF Code First - Foreign Keys Aren't Correct

I am trying to create a 1 to 1 relationship between two entities where both ends are required. They're basic entities, like this
public class EntityA
{
public int? EntityAID {get; set;}
public virtual EntityB EntityB {get; set;
}
public class EntityB
{
public int? EntityBID {get; set;}
public virtual EntityA EntityA {get; set;
}
I have an EntityTypeConfiguration object for EntityA that I use to configure the relationship. I want entityA to be the principal in the relationship, which, if I understand this process correctly, means EntityB will have a foreign key to EntityA in its database table. Here is my configuratoin statement
HasRequired(e=>e.EntityB).WithRequiredPrincipal(e=>e.EntityA);
I am updating my database with Code First Migration. When I generate the migration that will setup this relationship, the migration is correctly identifying the fact it needs to put a foreign key on the table for EntityB, however it is creating the foreign key to the table for EntityA with the primary key for EntityB, like this:
.ForeignKey("dbo.TableForEntityB", t => t.EntityBID)
It should be using the ID for EntityA as the foreign key.
Does anybody see what I'm doing wrong? I'm stumped. I've tried using WithRequiredDependent, and all that does is create an identical situation on TableForEntityA.
Thanks.
I am doing guess work here but I think the foreign key being created is not on primary key for EntityB table as well. EntityBID in the EntityB class is not the primary key for EntityB obviously because you are specifying it as a Nullable type, so what is it?
This stemmed from my misunderstanding of the one to one relationship as implemented by EF. I read up and found out that EF used a shared primary key relationship when making one to one relatoinships. So I changed EntityB to look like this:
public class EntityB
{
public int? EntityAID {get; set;}
public virtual EntityA EntityA {get; set;
}
And then configured the relationship like this:
HasRequired(c => c.EntityA).WithRequiredDependent(p => p.EntityB);
when configuring EntityB.

asp.net MVC3 application flow

I am working on an asp.net application. I need help designing the database related model and linq queries.
I have three tables ( and two lookup tables).
1)Product header (product header id as Primary key)
2) Product Detail(it has product header id as foreign key)
3) product attachment (it has product detail id as foreign key)
Now, I need to insert record in db.
a) for one Product header record there can be multiple Product detail records
b) for multiple product detail records, there can be multiple attachments.
I have created three entities for each tables. Product header also has two keys from user table and history table. but on view I need to show the user name instead of the key. Should I create a view model class which will hold all these entity classes as properties and how can I make sure that there first record is inserted in product header, then product details and then product attachment ?
Please suggest.
Thanks
an easy way to do this is to use the new Code First Feature that comes with EF 4.1
you can create your "entities" like so:
public class ProductHeader
{
public int ID {get; set;}
public virtual ICollection<ProductDetail> ProductDetails {get; set;}
//Other properties
}
public class ProductDetail
{
public int ID {get; set;}
public virtual ICollection<ProductAttachment> ProductAttachments {get; set;}
//Other properties
}
public class ProductAttachment
{
public int ID {get; set;}
// you can have a navigation property here for the user, this allows you to access his name
public virtual User User {get; set;}
//Other properties
}
public class MyContext:DbContext
{
public DbSet<ProductHeader> ProductHeaders {get; set;}
public DbSet<ProductDetail> ProductDetails {get; set;}
public DbSet<ProductAttachment> ProductAttachment {get; set;}
}
for the insertion order, just add your ProductHeader (after adding the ProductDetails and ProductAttachments to it) and EF will take care of it.
EDIT:
here's a sample code for adding a ProductHeader:
var context=new MyContext();
var ph=new ProductHeader();
ph.User=user;
var pd=new ProductDetail();
pd.ProductAttachments.Add(new ProductAttachment());
ph.ProductDetails.Add(pd);
context.ProductHeaders.Add(ph);
context.SaveChanges();
Hope this helps.

Resources