Entity Framework table creation - entity-framework

I have a model which looks like below
public class Employee
{
public int Id { get; set; }
public string Email { get; set; }
public string Forename { get; set; }
}
And I have an configuration file as below
public class EmmployeeConfiguration : EntityTypeConfiguration<Employee>
{
public EmmployeeConfiguration()
{
Property(e => e.Forename).IsRequired();
}
}
And I want it to create a table with Name of HR.Employee (HR being the schema). So, in my DbContext, I added the following.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Employee>().ToTable("Employee", schemaName: "HR");
modelBuilder.Configurations.Add(new EmmployeeConfiguration());
//base.OnModelCreating(modelBuilder);
}
I am expecting the database name to be "HR.Employee", but instead when i run "Enable-Migration", it is always trying to create "dbo.Employees".
Can someone point me what I am missing?

Related

EF Core TPH Discriminator ignores base entities

I have two DbContext. A BaseDbContext and one that inherits from the BaseDbContextcalled FemaleDbContext.
public class BaseDbContext : DbContext
{
public BaseDbContext(DbContextOptions options) : base(options) { }
public virtual DbSet<Person> Person { get; set; }
public virtual DbSet<House> House { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().ToTable("Person", "dbo");
modelBuilder.Entity<House>().ToTable("House", "dbo");
modelBuilder.Entity<Person>().HasOne(e => e.House).WithMany(e => e.Persons);
modelBuilder.Entity<House>().HasMany(e => e.Persons).WithOne(e => e.House);
}
}
The goal is to extend the Person entity with another property. I do not want to use shadow properties because its too dynamic. So I am trying to make it work using TPH. Here is my other context:
public class FemaleDbContext : BaseDbContext
{
public DbSet<Female> Female { get; set; }
public FemaleDbContext(DbContextOptions<FemaleDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Female>().HasBaseType<Person>();
base.OnModelCreating(modelBuilder);
}
}
As you can see, my sub-context should use the Female entity instead of the Person. The problem is that when I run this.Context.Female.ToList() on my SubDbContext, only entities with the value Female inside the Discriminator field inside my database are returned. Entities with the value Person in that table are returned. But I want to get every entity.
Also, here are my entities:
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Middlename { get; set; }
public string Lastname { get; set; }
}
public class Female : Person
{
public bool? IsPregnant { get; set; }
}
How can I configure my DbContext that this.Context.Female.ToList() returns both Females and Persons. Note that this.Context.Person.ToList() already returns everything, not only Persons

ef core 1.1 Autogenerated column using ValueGeneratedOnAdd

Using EfCore 1.1, I am trying to have a autogenerated column using ValueGeneratedOnAdd. The problem is i am always getting value as "0". Do i have to manually do anything with the database table ?
Here is my model
public class Contact
{
public int Id { get; set; }
// This needs to be auto generated
public Int32 ContactIndex { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public DateTime LastAccessed { get; set; }
}
This is how my OnModelCreating looks like
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>()
.Property(c => c.ContactIndex)
.ValueGeneratedOnAdd();
// I tried following as well but it did't work
// .HasDefaultValueSql("IDENTITY(int, 1,1)");
;
}
ok I figured how to do it, but i really wanted to do that without using any annotations, and i still cannot figure out how to do it without annotations on model. So here is my solution.
You need to annotate your filed in the model like following
public class Contact
{
public int Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int32 ContactIndex { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public DateTime LastAccessed { get; set; }
}
and add OnModelCreating in your context class. This will tell entity framework to ignore the column while adding or updating records. Make sure you calling method .ValueGeneratedAddOrUpdate( ). If you use only .ValueGeneratedAdd( ) you will get errors while making updates.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>()
.Property(c => c.ContactIndex)
.ValueGeneratedOnAddOrUpdate();
;
}
Generate and run your migrations and your migrations should include "SqlServerValueGenerationStrategy.IdentityColumn"
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "ContactIndex",
table: "Contact",
nullable: false,
defaultValue: 0)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
}

How do I force generated many-to-many Relation tables to the correct schema?

I have tables parkpay.User and parkpay.Role. EF Code First automatically generates a third table linking the two for a many-to-many relationship, but it generates dbo.UserRole. How do I get it to make that table `parkpay.UserRole'?
Use EntityTypeConfiguration<> config many-to-many mappings.
public class User
{
public long Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class Role
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class UserMapping : EntityTypeConfiguration<User>
{
public UserMapping()
{
ToTable("User", "parkpay");
HasKey(e => e.Id).Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasMany(e => e.Roles).WithMany(e => e.Users).Map(m => m.ToTable("UserRole", "parkpay").MapLeftKey("RoleId").MapRightKey("UserId"));
}
}
public class RoleMapping : EntityTypeConfiguration<Role>
{
public RoleMapping()
{
ToTable("Role", "parkpay");
HasKey(e => e.Id).Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class DatabaseContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new RoleMapping());
base.OnModelCreating(modelBuilder);
}
}

Table per Concrete Type Mapping Issue in EF Code First 4.2

I'm getting a EntityType 'User' has no key defined. Define the key for this EntityType error.
Model:
public abstract class KeyedEntityBase
{
public int ID { get; private set; }
}
public class User : KeyedEntityBase
{
public string UserName { get; private set; }
public string EmailAddress { get; private set; }
}
Context:
public class LSBPortalContext : DbContext
{
public LSBPortalContext()
: base("LSBPortalDB")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("User");
});
base.OnModelCreating(modelBuilder);
}
}
The issues was that I didn't actually map the KeyedEntityBase class. Once I did that it all worked properly.

in entity framework code first, how to use KeyAttribute on multiple columns

I'm creating a POCO model to use with entity framework code first CTP5. I'm using the decoration to make a property map to a PK column. But how can I define a PK on more then one column, and specifically, how can I control order of the columns in the index? Is it a result of the order of properties in the class?
Thanks!
NOTE:
As of 2019 this answer became non-valid for later EntityFramework versions.
You can specify the column order in the attributes, for instance:
public class MyEntity
{
[Key, Column(Order=0)]
public int MyFirstKeyProperty { get; set; }
[Key, Column(Order=1)]
public int MySecondKeyProperty { get; set; }
[Key, Column(Order=2)]
public string MyThirdKeyProperty { get; set; }
// other properties
}
If you are using the Find method of a DbSet you must take this order for the key parameters into account.
To complete the correct answer submitted by Slauma, you can use the HasKey method to specify an order for composite primary keys as well:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
}
public class Ctp5Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasKey(u => new
{
u.UserId,
u.Username
});
}
}
If, like me, you prefer to use a configuration file you can do that in this way (based on Manavi's example):
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
ToTable("Users");
HasKey(x => new {x.UserId, x.Username});
}
}
Obviously you have to add the configuration file to your context:
public class Ctp5Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserConfiguration());
}
}
Use as a anonymous object:
modelBuilder.Entity<UserExamAttemptQuestion>().ToTable("Users").HasKey(o => new { o.UserId, o.Username });