Entity Framework Code First - Defining Relationships/Keys - entity-framework

I am designing my database using code first and I need a little help I think.
I am getting this error:
Introducing FOREIGN KEY constraint 'SalesOrder_Invoices' on table 'Invoices' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
I am trying to have the following relationships/keys:
--> = 1 to Many Relationship
Customer --> CustomerLocation
CustomerLocation --> SalesOrder
SalesOrder --> Invoice
SalesRep --> SalesOrder
PaymentTerm --> Customer
PaymentTerm --> SalesOrder
PaymentTerm --> Invoice
I am trying to define them by the standard of:
<ClassName><PrimaryKeyID>
Example: Customer has ID property, so in CustomerLocation i define the foreign key like so:
Public Property CustomerID AS Integer
All I have to do is define the foreign key correct? Do I also have to have navigation properties for each key I define?
And, can I not have multiple foreign keys on the same primary key of an object?
Updated
So to define a relationship, do you use the ClassName.PrimaryKeyProperty? or do you use navigation properties? Or both? Confused!!
Update 2
So to make a relationship work you have to define both sides... I think.
Public Class Customer
Public Property ID AS Integer
Public Overrideable Property Locations AS ICollection(OF CustomerLocation)
End Class
Public Class CustomerLocation
Public Property ID AS Integer
Public Property CustomerID AS Integer
End Class

This is exception caused by SQL server when you have multiple paths of cascade deletes. If you delete your PaymentTerm it will trigger cascade delete on all three relations. This will blow up when creating either SalesOrder or Invoice. EF creates by default all one-to-many relations with ON DELETE CASCADE you can remap your specific relation to not use it by:
modelBuilder.Entity<...>()
.HasRequired(...)
.WithMany(...)
.HasForeignKey(...)
.WillCascadeOnDelete(false);
Or you can turn it off globaly by removing the convention:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
You can get around this error on a particular migration by editing the generated Up() method with a line something like this:
AddForeignKey("dbo.Payments", "EventID", "dbo.Events", "EventID", cascadeDelete: true)
and change that cascadeDelete: value to false on the offending relationship(s).

Read this, I am sure this will help you find the answer.
Also, according to ScottGu's blogpost, I think in general it should be that you just create the classes as follows (I didn't read it carefully enough, so you should check it out for further details):
public class Customer
{
public int CustomerID { get; set; }
public int CustomerLocationID { get; set; }
public virtual CustomerLocation Location { get; set; }
}
public class CustomerLocation
{
public int CustomerLocationID { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}

Related

EF Core: Change naming strategy of FK Shadow Properties?

In EF Core, when defining Relationships, one can either provide the necessary FK properties explicitly or not:
Explicit FK property:
public class Person
{
public Guid Id { get; set; }
public ICollection<ParentIdentity> Identities { get; set; }
...
}
public class PersonIdentity
{
public Guid Id { get; set; }
public PersonFK { get; set; } //Explicit Data storage FK field in System Logic Entity :-(
...
}
The relationship would be defined in Fluent API as follows:
model.HasMany(x => Identities) // Person can have multiple identities
.WithOne() // Identity does not need a Nav property back up to Person
.WithForeignKey(x => x.PersonFK) // Hardcoded the FK.
The upside is its eminently clarity of how it's hooked up.
The downside is the blurring of domains between system logic and storage -- in that the system entity now has Data storage specific attributes (PersonFK) that have nothing to do with system logic that developers should be concentrating on.
Shadow properties
The alternative is to let EF sort it out, using shadow properties, by not define an FK Property on the Entity:
public class Person
{
public Guid Id { get; set; }
public ICollection<ParentIdentity> Identities { get; set; }
...
}
public class PersonIdentity
{
public Guid Id { get; set; }
...
}
And define the relationship as follows:
model.HasMany(x => Identities) // Person can have multiple identities
.WithOne() // Identity does not need a Nav property back up to Person
//.WithForeignKey(x => x.PersonFK) // Don't provide an FK property
;
EF will step up and add a property to the db table named to the following convention:
<principal primary key property name>Id
//ie, will be created as `PersonId`
But let's say I want to change it to:
<principal primary key property name>FK
//ie, will be created as `PersonFK`
Question
How?
Foraging so far
In case it helps, I'm looking in the following direction:
I can see a SqlServerConventionSetBuilder that inherits from RelationalConventionSetBuilder that inherits from ProviderConventionSetBuilder.
ProviderConventionSetBuilder in turn calls
ForeignKeyIndexConvention
ForeignKeyPropertyDiscoveryConvention
ForeignKeyAttributeConvention
found some sparse documentation at https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.metadata.conventions.foreignkeyindexconvention?view=efcore-6.0
but not enough there to know where to look really.
Can someone point me in the right direction as to:
what convention to replace
how to replace it easily?
Thank you!

Entity framework, find method leaves foreign key empty

I have an entity named PageItem. PageItem has a property named Page. Type of Page is Page class.
class PageItem {
public Page Page { get; set; }
...
}
when I query like this:
var item = context.PageItems.Find(5);
Problem is, item.Page is null, so when I save item entity framework creates a new page record.
Summary of what I learned:
First: entity framework Find method does not fill Id value of nested objects (in database language: foreign keys. But I realized than when you save that entity, it does not update foreign key columns, so nothing is broken.
Seconly: if you want to read, and use foregin key values of an entity, you should define (int/long whatever) properties per referanced table an foreign key. And mark it with ForeignKey attribute. Also if it can be null, make property type int? or long? (nullable)
Sample:
pubclic class Customer {
public Id { get; set; }
[ForeignKey("City")}
public int? City_Id { get; set; }
public City City { get; set; }
}
Also if you want layz loading on City, you have to mark it virtual.

entity framework table with optional foreign keys

First of all, I'm new to Entity Framework and I'm trying to do a project using the Code-First model, so please forgive my ignorance on what may turn out to be a trivial problem...
I'm working on creating some POCO EF classes and I'm having difficulty figuring out how to setup some of the relationships in the DbContext derived class.
If I were to setup the tables with SQL, this is what they would look like (extraneous columns removed for clarity and brevity:
CREATE TABLE DBO.Application (
ApplicationId NUMERIC(18,0) IDENTITY(1,1) NOT NULL,
MinimumVersionId NUMERIC(18,0),
CurrentVersionId NUMERIC(18,0));
CREATE TABLE DBO.ApplicationVersion (
ApplicationVersionId NUMERIC(18,0) IDENTITY(1,1) NOT NULL,
ApplicationId NUMERIC(18,0) NOT NULL;
ALTER TABLE DBO.Application ADD
PRIMARY KEY (ApplicationId),
CONSTRAINT Application_FK1
FOREIGN KEY (MinimumVersionId)
REFERENCES DBO.ApplicationVersion (ApplicationVersionId),
CONSTRAINT Application_FK2
FOREIGN KEY (CurrentVersionId)
REFERENCES DBO.ApplicationVersion (ApplicationVersionId);
ALTER TABLE DBO.ApplicationVersion ADD
PRIMARY KEY (ApplicationVersionId),
CONSTRAINT ApplicationVersion_FK1
FOREIGN KEY (ApplicationId)
REFERENCES DBO.Application (ApplicationId);
The relevant part of the ApplicationModel POCO class is (Application DB Table shown above):
public class ApplicationModel
{
public long ApplicationId { get; set; }
public virtual ApplicationVersionModel CurrentVersion { get; set; }
public long? CurrentVersionId { get; set; }
public virtual ApplicationVersionModel MinimumVersion { get; set; }
public long? MinimumVersionId { get; set; }
public virtual IList<ApplicationVersionModel> Versions { get; set; }
}
And the ApplicationVersionM POCO class (ApplicationVersion DB Table shown above):
public class ApplicationVersionModel
{
public virtual ApplicationModel Application { get; set; }
public long ApplicationId { get; set; }
public long ApplicationVersionId { get; set; }
}
So far, in the OnModelCreating method of the class that inherits from DbContext, I have this:
modelBuilder.Entity<ApplicationModel>()
.HasMany<ApplicationVersionModel>(a => a.Versions)
.WithRequired(av => av.Application)
.HasForeignKey(a => a.ApplicationId);
This is to establish the one to many relationship between Application and ApplicationVersion.
Where I'm getting confused is how to write the entries for the CurrentVersion and MinimumVersion fields. Each of these are to hold a value that would be found in ApplicationVersion.ApplicationVersionId (the primary key). However, these fields are nullable in the database and, therefore, optional.
I'm getting lost in all the options like:
WithMany - I know this one isn't it as I'm pointing to a single record
WithOptionalDependant
WithOptionalPrincipal
WithRequired - I don't think this is it since the field is nullable
And then, I'm not exactly sure what methods would be chained after that.
Any help would be appreciated. It would also be beneficial if, in your answers, you could explain WHY I need to do it that way. Knowing why will help me (and possibly others that may read the question) understand the processes and relationships better.

Code First: Independent associations vs. Foreign key associations?

I have a mental debate with myself every time I start working on a new project and I am designing my POCOs. I have seen many tutorials/code samples that seem to favor foreign key associations:
Foreign key association
public class Order
{
public int ID { get; set; }
public int CustomerID { get; set; } // <-- Customer ID
...
}
As opposed to independent associations:
Independent association
public class Order
{
public int ID { get; set; }
public Customer Customer { get; set; } // <-- Customer object
...
}
I have worked with NHibernate in the past, and used independent associations, which not only feel more OO, but also (with lazy loading) have the advantage of giving me access to the whole Customer object, instead of just its ID. This allows me to, for example, retrieve an Order instance and then do Order.Customer.FirstName without having to do a join explicitly, which is extremely convenient.
So to recap, my questions are:
Are there any significant disadvantages in
using independent associations? and...
If there aren't any, what
would be the reason of using foreign key associations at all?
If you want to take full advantage of ORM you will definitely use Entity reference:
public class Order
{
public int ID { get; set; }
public Customer Customer { get; set; } // <-- Customer object
...
}
Once you generate an entity model from a database with FKs it will always generate entity references. If you don't want to use them you must manually modify the EDMX file and add properties representing FKs. At least this was the case in Entity Framework v1 where only Independent associations were allowed.
Entity framework v4 offers a new type of association called Foreign key association. The most obvious difference between the independent and the foreign key association is in Order class:
public class Order
{
public int ID { get; set; }
public int CustomerId { get; set; } // <-- Customer ID
public Customer Customer { get; set; } // <-- Customer object
...
}
As you can see you have both FK property and entity reference. There are more differences between two types of associations:
Independent association
It is represented as separate object in ObjectStateManager. It has its own EntityState!
When building association you always need entitites from both ends of association
This association is mapped in the same way as entity.
Foreign key association
It is not represented as separate object in ObjectStateManager. Due to that you must follow some special rules.
When building association you don't need both ends of association. It is enough to have child entity and PK of parent entity but PK value must be unique. So when using foreign keys association you must also assign temporary unique IDs to newly generated entities used in relations.
This association is not mapped but instead it defines referential constraints.
If you want to use foreign key association you must tick Include foreign key columns in the model in Entity Data Model Wizard.
Edit:
I found that the difference between these two types of associations is not very well known so I wrote a short article covering this with more details and my own opinion about this.
Use both. And make your entity references virtual to allow for lazy loading. Like this:
public class Order
{
public int ID { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; } // <-- Customer object
...
}
This saves on unnecessary DB lookups, allows lazy loading, and allows you to easily see/set the ID if you know what you want it to be. Note that having both does not change your table structure in any way.
Independent association doesn't work well with AddOrUpdate that is usually used in Seed method. When the reference is an existing item, it will be re-inserted.
// Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);
// New order.
var order = new Order { Id = 1, Customer = customer };
db.Set<Order>().AddOrUpdate(order);
The result is existing customer will be re-inserted and new (re-inserted) customer will be associated with new order.
Unless we use the foreign key association and assign the id.
// Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);
// New order.
var order = new Order { Id = 1, CustomerId = customer.Id };
db.Set<Order>().AddOrUpdate(order);
We have the expected behavior, existing customer will be associated with new order.
I favour the object approach to avoid unnecessary lookups. The property objects can be just as easily populated when you call your factory method to build the whole entity (using simple callback code for nested entities). There are no disadvantages that I can see except for memory usage (but you would cache your objects right?). So, all you are doing is substituting the stack for the heap and making a performance gain from not performing lookups. I hope this makes sense.

EF Code First giving me error Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF. [duplicate]

This question already has answers here:
EF code first: Cannot insert explicit value for identity column in table '' when IDENTITY_INSERT is set to OFF
(3 answers)
Closed 4 years ago.
I'm trying out Entity Framework 4's Code First (EF CodeFirst 0.8) and am running into a problem with a simple model that has a 1 <--> 0..1 relationship, between Person and Profile. Here's how they're defined:
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? DOB { get; set; }
public virtual Profile Profile { get; set; }
}
public class Profile
{
public int ProfileId { get; set; }
public int PersonId { get; set; }
public string DisplayName { get; set; }
public virtual Person Person { get; set; }
}
The DB context looks like this:
public class BodyDB : DbContext
{
public DbSet<Person> People { get; set; }
}
I didn't define a DbSet for Profile because I consider People to be its aggregate root. When I try to add a new Person - even one without a Profile with this code:
public Person Add(Person newPerson)
{
Person person = _bodyBookEntities.People.Add(newPerson);
_bodyBookEntities.SaveChanges();
return person;
}
I get the following error:
Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF.
The newPerson object has a 0 for the PersonId property when I call People.Add(). The database tables are People and Profiles. PersonId is the PK of People and is an auto-increment Identity. ProfileId is the PK of Profiles and is an auto-incement Identity. PersonId is a non-null int column of Profiles.
What am I doing wrong? I think I'm adhering to all the EF Code First's convention over configuration rules.
I get the following error:
Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF.
I think that the IDENTITY_INSERT is the Auto Increment functionality which is off.
So, check the field PersonId in the database to see if it is an identity.
Besides, maybe this will fix your problem too.
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int PersonId { get; set; }
This will occur if you perform the following steps:
Create a non-identity PK field on a table.
Infer the Entity Model from that table.
Go back and set the PK identity to true.
The Entity Model and the database are out of sync. Refreshing the model will fix it. I had to do this just yesterday.
If you are using EF Code First, then, in addition to adding the [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] annotation attribute to the model.cs file as others have suggested here, you also need to make the same effective change on the modelMap.cs files (the fluent mapping instructions):
Change from:
this.Property(t => t.id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
to:
this.Property(t => t.id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
(I used the EF Power Tools to generate the entity models and the default mapping files, then later turned one Id column into a prmary key column and set it to IDENTITY in Sql Server, therefore, I had to update the attribute and the default mapping file.)
If you don't change it in both places, you'll still get the same error.
You situation reminds me situation I experience with EF Code First when PrimaryKey and ForeignKey are the same column.
There is no direct way to refresh the model, however the same effect can be achieved in 2 steps.
Comment out ProfileId in Profile class. Recompile and update database.
Uncomment Profile Id, add DatabaseGeneratedAttribute and update database again.
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None), Key]
This way the generated ProfileId column becomes Key without Identity.
If you are using EF core and the fluent interface like me, I've found that the Scaffold-DbContext utility I've used to create the model from an existing db, generate a line for my column like that:
entity.Property(e => e.id).ValueGeneratedNever();
After I've changed the DB adding the IDENTITY attribute to my id, I had to change the row in:
entity.Property(e => e.id).ValueGeneratedOnAdd();
other than adding the [DatabaseGeneratedAttribute(DatabaseGeneratedOption.None), Key] decorator to the id field in my model class.
I'm not even sure if the latter is necessary. After resolved with the former fix, I didn't try to remove it.
I didn't have this problem until I added a composite key , so once I had 2 primary keys this occurred with EF 6.x.x
On my Key "Id" which has Identity Specification set to true I needed to add
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
Model properties now:
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[Key, Column("Id", Order = 1)]
public int Id { get; set; }
[Key, Column("RanGuid", Order = 2)]
public string RanGuid { get; set; }
For the benefit of searchers: I got this error, but the above fixes did not work. It was due to an error on my part.
On my tables, I have a Guid Primary Key (non-clustered) and an int index.
The error was happening when trying to update the 'Post' with the 'Blog' info as a navigation property. See classes below:
public class Blog
{
public Guid BlogId { get; set; }
public int BlogIndex { get; set; }
// other stuff
}
public class Post
{
public Guid PostId { get; set; }
public int PostIndex { get; set; }
// other stuff
public Blog Blog { get; set; }
}
The issue was that when I was converting DTO's to models, the BlogId was being changed to a new Guid() (I made an error in the mapping). The resulting error was the same as detailed in this question.
To fix it, I needed to check the data was right when being inserted (it wasn't) and fix the incorrect change of data (in my case, the broken mapping).
Got this error in EF6, looked at the database and everything looked right with Identity Specification set to Yes. I then removed the different migrations and made one new migration from current models and then everything started working. Fastest solution since the application was not live yet and still in development.
Cannot insert explicit value for identity column in table
'Test' when IDENTITY_INSERT is set to OFF.
Here is the solution. Also see the attachment for more help.
Navigate to your EF model ".edmx" file >> Open it >> Now right click on the diagram and choose 'Update Model from Database'.
This will fix it because you made PK the Identity in your DB after you created your EF model.
help to recreate steps stated above
In my case it seems that EF doesn't like other type than INT identity field - mine was a BYTE (TINYINT on the SQL side).
Since I was able to update my project and change it to INT on the SQL, after re-running the Reverse Engineering Code First on VisualStudio, the error has immediately ceased to occur.
In my case it seems that EF doesn't like other type than INT identity field - mine was a BYTE (TINYINT on the SQL side).
I had this error too using PK of tinyint type. It's not that EF doesn't like it, it's seems that, unlike other cases, you have to specify that in your configuration like this:
this.Property(t => t.TableID).HasColumnName("TableID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);