Please see the class below:
public class UndergraduateEntityTypeConfiguration : IEntityTypeConfiguration<Undergraduate>
{
public void Configure(EntityTypeBuilder<Barclaycard> undergraduateConfiguration)
{
undergraduateConfiguration.HasData(
new Undergraduate(1, "Undergraduate")
);
}
}
and the code below:
public class StudentEntityTypeConfiguration : IEntityTypeConfiguration<Student>
{
public void Configure(EntityTypeBuilder<CreditCard> studentConfiguration)
{
studentonfiguration.ToTable("Student", StudentContext.DEFAULT_SCHEMA);
studentConfiguration.HasKey(o => o.Id);
studentConfiguration.Property(o => o.Id)
.ForSqlServerUseSequenceHiLo("studentseq", StudentContext.DEFAULT_SCHEMA);
studentConfiguration.HasDiscriminator<string>("Type")
.HasValue<Graduate>("Graduate")
.HasValue<Vanquis>("Undergraduate");
}
}
Notice the Student ID field (in the Student table) uses a HiLo sequence. However, in UndergraduateEntityTypeConfiguration I have to explicitly pass an ID number to the Undergraduate constructor to add the Undergraduate record to the Student table.
The code works as expected. However, I am confused why I have to pass an ID (1) myself. Is there a way of creating the Undergraduate record like this:
undergraduateConfiguration.HasData(
new Undergraduate("Undergraduate")
);
Note that this time no ID is passed to the constructor. If I do this, then I see an error, which says: "The seed entity for entity type 'Undergraduate' cannot be added because there was no value provided for the required property 'Id'".
No. This is a specific requirement for EF Core data seeding with HasData (a.k.a Model seed data) coming from the design of the feature.
It's not specific for HiLo sequence generated columns, but all auto generated columns (including the most used auto increment (identity) and database sequence generated columns). The explanation in the documentation is as follows (pay special attention to the first bullet):
This type of seed data is managed by migrations and the script to update the data that's already in the database needs to be generated without connecting to the database. This imposes some restrictions:
The primary key value needs to be specified even if it's usually generated by the database. It will be used to detect data changes between migrations.
Previously seeded data will be removed if the primary key is changed in any way.
If it's a problem for you, consider switching to the more traditional way of data seeding.
Related
I'm new to Entity Framework in C#.
I'm having one computational column in my table table1(example). I will calculate the computational column value based on the other columns value. I don't want Entity Framework to include the computational column while performing insert/update operations. How can I make the EF to avoid that particular column. But I want to set the value for that particular column manually.
I searched for the same but i couldn't able to get the answer for my question. Kindly help me and thanks in advance.
You can use the NotMapped Annotation
Code first convention dictates that every property that is of a
supported data type is represented in the database. That property can
be created dynamically and does not need to be stored. You can mark
any properties that do not map to the database with the NotMapped
annotation.
[NotMapped]
public string Something
{
get
{
return _something;
}
set
{
_something = value
}
}
Update : this is will not map to the dB, so is probably not what you are looking for
Just to make this a more complete the DatabaseGenerated Annotation, are the droids you are looking for
An important database features is the ability to have computed
properties. If you're mapping your Code First classes to tables that
contain computed columns, you don't want Entity Framework to try to
update those columns. But you do want EF to return those values from
the database after you've inserted or updated data. You can use the
DatabaseGenerated annotation to flag those properties in your class
along with the Computed enum. Other enums are None and Identity.
Which can be used with the DatabaseGeneratedOption
Computed : The database generates a value when a row is inserted or updated.
Identity : The database generates a value when a row is inserted.
None : The database does not generate values.
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
public string Something { get; set; }
As you calculate your column server side the correct way is to configure the field at the context level with:
HasComputedColumnSql for ef-core
DatabaseGeneratedAttibute for EF-6 (HasDatabaseGeneratedOption for the fluent api)
If you use NotMapped, you will not get the value from the database.
Basically I know that find() works when it checks the entity by the stated primary id. My question is I have a Model and one of its property have [Key] data annotation but this column is not the actual primary key in the database.
Something like this
public class ModelMetadata (I'm using a metadata)
{
public int ID{get;set;} <<--actual rownum or db id
[Key]
public guid ItemId{get;set;} <<-- my desired id for find()
public string prop1{get;set;}
}
now if I use dbcontext.Model.Find(id) will it return the result based on the 'ItemId'? or the actual assign Primary key 'ID'?
Thank you.
Use a where conditional single or default like
User myUser = myDBContext.Users.SingleOrDefault(user => user.Username == username);
From Programming Entity Framework: DbContext:
One of the great things about Find is that it doesn't unnecessarily
query the database. It's also capable of finding newly added objects
that haven't yet been saved to the database. Find uses a simple set of
rules to locate the object (in order of precedence):
Look in memory for an existing entity that has been loaded from the database or attached to the context.
Look at added objects that have not yet been saved to the database.
Look in the database for entities that have not yet been loaded into memory.
I have a case where I need to add a Guid Property that is NOT the primary key, and that could be shared with several objects in the table.
What I'd like to do is:
Generate the Guid on the database when I don't give it a value
Set a Guid (instead of generating it) when I have its value
Both of this would be done on Insert only, Updates won't touch these values.
What I have tried:
Add the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute: only works when I don't need to set the Guid manually
Add the [DatabaseGenerated(DatabaseGeneratedOption.Computed)] attribute: doesn't work when I don't set the Guid manually
I've seen quite a lot about this topic, and the closest thing would be this article:
http://www.davepaquette.com/archive/2012/09/23/calculated-columns-in-entity-framework-code-first-migrations.aspx
But we don't (and won't) use Migration in our project, so that doesn't seem fit.
or this SO question, but that would mean generating Guids in .Net (which doesn't seem to be very clean, at least in my opinion): EF, Code First - How to set a custom Guid identity value on insert
Is there a way to generate the Guid Database side, AND set it when I need to in EF Code first?
If not, what would be a good alternative? Is it really a bad idea to generate Guids on the .Net side? (I could go with that if nothing else is possible)
I will assume that you are using MS-SQL , then you can do the following
To use the execute command
public class YourDbContext: DbContext
{
public YourDbContext():base("ConnectionString")
{
if (Database.Exists())
{
Database.ExecuteSqlCommand("if object_id('CT_DefaultGuid') is null alter table YourTable add constraint CT_DefaultGuid default newid() for YourColumn");
}
}
}
To set the Id from .Net, you can do the following
Create a Base Entity contains Id property
In the constructor you check if the Id is empty then initialize it
Let all the entities you have to inherits from this class
Your base class should look like
public class BaseEntity
{
public BaseEntity()
{
if(Id==Guid.Empty)
Id = Guid.NewGuid();
}
public Guid Id{get;set;}
}
To use the migration for existing database
from PMC => Enable-migrations
from PMC => Add-Migration "FirstRun"
open the generated migration file and make sure to empty the Up and Down methods ( this will not apply any changes on the database)
Add the corresponding alter column fluent code using Sql("") method in the Up method
from PMC => Update-Database -Script , to make sure that only sql statement generated is the alter table statement
from PMC => once you are sure that the desired statement is the only appearing in the SQL script , then apply : Update-Database.
Your class should like this
public class FirstRun : DbMigration
{ public override void Up()
{
Sql("alter table YourTable add constraint CT_DefaultGuid default newid() for YourColumn");
}
}
I recommend the last approach, it will be executed once, and you can add changes later to your database.
Hope this will help you
I have a code first project with a few tables, I am trying to determine that for a certain object the Id with which it will be inserted will not be the sequential Id that sql provides but an Id i will provide.
Although the code in my repository is creating the object properly and assigns it the wanted Id once it is inserted to my DB in the:
DbContext.Set<Containers>().Add(entity);
It is inserted as the next sequential Id.
In my code first the Id column for the base Entity from which all my entities derive is:
public int Id { get; set; }
I am looking the change to the Id's only in this entity.
Any suggestions?
this is the default behavior: when you don't alter it explicitly, EF will create an autoincrement column on the ID, if it's type is fitting.
To alter it, use Fluent API:
modelBuilder.Entity<Containers>().Property(x=>x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
or Data annotations:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
Maybe you'll have to run an migration after this to alter the table to non-autoincrement also. If you don't want to do that, you'll have to use Identity insert, wrapped in a transaction, every time you want this behavior.
Problem is simple I have two classes mapped with fluent nhibernate :
public class A: EntityBase {}
public class B: EntityBase
{
public virtual A A_Something {get;set;}
}
with EntityBase class providing only Key property. Now i want to map them and configure my db. So here are mappings
public class AMap : DomainEntityBase<A>
{
public AMap(){}
}
public class BMap : DomainEntityBase<B>
{
public BMap()
{
References(p=>p.A_Something).Column("A_ID");
}
}
and db configuration
Fluently.Configure().Database(...).Mappings(m =>
m.FluentMappings.Add<BMap>()).
ExposeConfiguration(BuildSchema).BuildSessionFactory();
Configuration is done only with BMap as unfortunately table A already exists inside database and it's data can't be changed (it's because this application is using parts of bigger database and those parts are not to be modified). So this schema generates standard exception
An association from the table [B] refers to an unmapped class: A
Is there any possibility somehow specify inside my configuration that A already exists in the db? If not what are your suggestions to solve this issue in a gentle way? Of course I can prepare *.sql files to manually create table B but this is not a solution (just pushing away problem as it will surely come back during further development). Also creating separate db and importing data from the first one could work but unfortunately there is a requirement to store data inside one (and only one) db.
You have to map all the entities you will use; whether or not their corresponding tables are present in the database is irrelevant.
Only when you are doing schema generation is it going to matter, but all you have to do is generate update scripts instead of create scripts. Given the database dialect and a connection, NHibernate will generate scripts to create missing tables and update existing tables, if necessary (which it sounds like it isn't in this case).
If the existing table's name does not match the type of the entity (the default name), you'll need to specify that in your mapping by calling:
Table("ATable");