How to map table name to EF Entity? - entity-framework

I have been using EF Code First for 1 month. My project needs to work with many tables (over 100 tables of data) and they will be changed many times in the future. It hard to control and take time to add the migration.
So is there any solution to skip the add-migration step, just create the table in the database and create a mapping to the Entity?
Example:
In database I have a table like this:
CREATE TABLE dbo.MyTable
(
Id INT,
Name VARCHAR(255),
Description VARCHAR(1000)
);
I want to map it to the following entity:
public class MyEntity
{
public Id int {get; set;}
public Name string {get; set;}
public Description string {get; set;}
}
My expected solution is something like this:
CreateMap("dbo.MyTable", MyEntity)

Use the attribute System.ComponentModel.DataAnnotations.Schema.Table
[Table("MyTable")]
public class MyEntity
{
public Id int {get; set;}
public Name string {get; set;}
public Description string {get; set;}
}
If you don't actually want to run the migrations, I suggest create them anyway and comment out the relevant code before you run them. That way you will be well set up for the occassion when you do actually want to run them.

You can define the entity maps by overriding the method called OnModelCreating in your DbContext:
Then you can add some maps similar to:
modelBuilder.Entity<Order>(m => {
m.ToTable("MyTable", "dbo");
})
Info: https://learn.microsoft.com/en-us/ef/core/modeling/relational/tables
EDIT: I don't like adding annotation directly to my entity as I prefer to centralize it in one place. Easier to manage. After all I guess it's a question of preferences :)

Related

What is the best practice regarding setting Id's of contained entities in entity framework core

Assuming i have the following entities that i store in a database using entity framework core
public class Container{
public int ContainerId {get; set;}
public int ContainedId {get; set;}
public Contained Contained {get; set;}
}
public class Contained {
public int ContainedId {get; set;}
public int ValueA {get; set;}
public int ValueB {get; set;}
}
if at some point in time i decide to save a Container class, with a know Contained class should i manually set the Id?
var containerToSave = new Container{
Contained = contained;
ContainedId = contained.ContainedId
}
or this is a bad practice? If I set it with an id that doesnt match the one in the actual class what will it save?
As far as Entity Framework goes you can specify either a foreign key or add the related entity when saving the main one.
To answer your question... No, is not a bad practice and this isn't related to the EF either. Rather your Container matches the Contained is a business related problem and should be treated and validated there. EF role in your case is to save the data whatever method you choose.
Assuming you mark the Contained EF will give you 2 choices:
public virtual Contained Contained { get; set; }
Add the foreign key:
var containerToSave = new Container
{
ContainedId = contained.ContainedId
}
Add the entity itself:
var containerToSave = new Container
{
Contained = new Contained
{
ValueA = x;
ValueB = y;
}
}
In you case, if you already have the Contained added, you can go with the first one but not the less, either of above methods are working just fine.

Table with with different fields depending on category

I have table that has these columns:
Id
Title
Description
CreateDateTime
CategoryId
Picture
quantity
Price
RentPrice
WantToExchange
NumberOfRoom
DepositPrice
Only the first 6 are required for each row and other column will be null based on entity category.
For example in cat1 only first 6 field and Price filled by user,and in cat2 only first 6 field and RentPrice, DepositPrice are filled, so after a while many column of table rows become a null
I see some solution in NopCommerce source code that used for store various product property in different language - there are entity called LocalizedProperty and storeEntityId, LanguageId, Name of entity, name of field and its value
it use
Expression<Func<T, TPropType>>
and PropertyInfo to get name of field, but I am searching for an easier way.
How can I redesign my entity?
If you'd have designed this object orientedly, you would probably have create a PictureDescription class, and a PicturePrice class, that would have the other properties.
Every PictureDescription would have zero or one PicturePrice object: a straightforward aggregation
If you want zero-or-one in a relational Database, then this is quite often done using two tables, with a foreign key from one table pointing to the other table.
See Entity Framework zero-or-one-to-one
class PictureDescription
{
public int Id {get; set;}
public string Title {get; set;}
...
// every PictureDescription has zero or one PicturePrice
public virtual PicturePrice PicturePrice {get; set;}
}
class PicturePrice
{
public int Id {get; set;}
public decimal Price {get; set;}
...
// every PicturePrice belongs to exactly one Picture, using foreign key
public int PictureDescriptionId {get; set;}
public virtual PictureDescription PictureDescription {get; set;}
}
This will be enough for entity framework to detect your columns and the relations between the tables. If you want to use fluent API, in DbContext.OnModelCreating:
// every PictureDescription has zero or one PicturePrice:
modelBuilder.Entity<PictureDescription>()
.HasOptional(description => description.PicturePrice)
.WithRequired(price => price.PictureDescription)
.HasForeignKey(price => price.PictureDescriptionId);

Add Navigation Property when column already exists

How can I add a navigation property to my context, when the corresponding column has already been created in the database from a previous migration?
For example: A lady has many cats. I want to add a LadyId property to the Cats class, but a LadyId column already exists in the Cats table. This LadyId column was created in a previous migration to accommodate the Cats.Lady navigation property.
DB:
Lady Table
--------------
Id Name
Cats Table
--------------
Id LadyId FurColor
Classes:
public class Lady {
public Id {get; set;}
public Name {get; set;}
public List<Cat> Cats {get; set;}
}
public class Cat {
public Id {get; set;}
public Lady Lady {get; set;}
//I want to add a LadyId property here
}
So far, I've tried...
Adding the property: Error: "The model backing the 'Context' context has changed..."
Adding a migration to update the DB: This creates a migration, but it just renames the column to LadyId1, which is pointless. The DB should remain the same, I just want to add a Navigation Property.
Commenting out code in migration Up and Down methods to try and "trick" the migration table into having the correct hash to match my context. This throws an error "Invalid column name 'EmployeePerformanceReview_id1"

Recurrency problem Entity Framework

I'm working with EF 4.1 CTP5 and SQL Server 2008. I need to understand how to solve a recurrency problem. I have the following 2 classes:
public class Nation
{
public int ID {get; set;}
public string name {get;set;}
public List<NationAlly> NationAllies {get;set;}
}
public class NationAlly
{
public int ID {get; set;}
public int level {get;set;}
public Nation Owner {get; set;}
public Nation toNation {get;set;}
}
The entities are mapped to the database with two tables (Nations and NationAllies). Besides, there are two relationships. 1) From NationAllies.OwnerID to Nation.ID
2) From NationAllies.ToNationID to Nation.ID
When I try to retrieve an object of Nation type from my database, I access the DbContext class NationDB:
Nation selectedNation = ((nationDB.Nations.Include("NationAllies")).Where(m => m.name == "France")).FirstOrDefault();
The problem is that I get a selectedNation object which has a list of NationAllies but every NationAlly in the list has the field toNation = null.
First of all I would like the field toNation to retrieve the correct information from the database. How do I do this?
Then of course toNation will be connected with other NationAllies which on their turn will have an other Nation. How could possibly a recursive map be built? My idea is to navigate the map until a certain level, by querying the database in a specific way. Doing so, what would be the best approach to have good speed performance?
It looks like NationAllies is junction table with additional properties. The problem is that EF doesn't eager load nested navigation properties if you do not specify them explicitly in Include method. If you want to have toNation filled you must use
nationDB.Nations.Include("NationAllies.toNation")
or
nationDB.Nations.Include(n => n.NationAllies.Select(na => na.toNation))
You can also enable lazy loading. Make all your navigation properties virtual (toNation, NationOwner and NationAllies) and unless you close the context all properties will be loaded once you first access them.

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