I am using EF Core 2.0 to create a table in which the primary key is a GUID and the clustered index is an auto-incrementing INT column. But I'm getting this error:
Cannot create more than one clustered index on table 'Tenants'. Drop the existing clustered index 'PK_Tenants' before creating another
This is the code for creating entity and Fluent API.
Tenant.cs
public class Tenant : EntityBase
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ClusteredId { get; set; }
public new Guid TenantId { get; set; }
public string TenantCode { get; set; }
}
FluentAPI
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Tenant>().HasIndex(c => c.TenantId).ForSqlServerIsClustered(false);
builder.Entity<Tenant>().HasIndex(c => c.ClusteredId).HasName("ClusteredId").ForSqlServerIsClustered(true);
base.OnModelCreating(builder);
}
Please suggest, how to remove this error and create primary key for GUID and clustered index for auto-incrementing INT column.
Thanks.
The PK index is not maintained explicitly. In EF Core it can be configured via KeyBuilder fluent API (note the HasKey in place of HasIndex):
builder.Entity<Tenant>().HasKey(c => c.TenantId).ForSqlServerIsClustered(false);
builder.Entity<Tenant>().HasIndex(c => c.ClusteredId).HasName("ClusteredId").ForSqlServerIsClustered(true);
Related
Given a database with a table A. I want to create a table B and add a one-to-may relation between A and B with a required foreign key.
For example suppose that have an existing table 'Users' and then we want to add 'Roles' to the existing users.
The code first definition of those entities is as follows:
public class User
{
public Id UserId { get; set; }
public string Email { get; set; }
public string UserName => Email;
public Roles Role { get; set; }
public int? RoleId { get; set; }
}
public class Roles
{
public string RoleName { get; set; }
public int RoleId { get; set; };
public ICollection<User> GetUsers { get; set; }
}
The Configure Method for the Users using Fluent API is as follows:
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("User");
builder.HasKey(t => t.UserId );
builder.Property(t => t.UserId ).ValueGeneratedOnAdd();
builder.HasOne(dt => dt.Role)
.WithMany(d => d.GetUsers)
.HasForeignKey(dt => dt.RoleId)
.HasConstraintName("ForeignKey_UserRole")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
}
Trying to run the migration I got this error message:
'The ALTER TABLE statement conflicted with the FOREIGN KEY constraint'
By splitting this migration in two migrations and seeding the data between the them allowed me to build the new database:
The first one remove the constrain IsRequired on the Fluent APi definition of the User entity and allowing null value for the foreign key RoleId.
Then Seed the database
Add the second and last migration to enable the constrain of the required foreign key RoleID in the User entity and removing the allows null on the foreign key.
My question is related to if there is an strategy that allows to add a new relation using code first approach with a required foreign key using only one migration?
Thank you
Francisco
How do you specify a custom column name with a HasOne relationship in EF7?
Consider the following sample classes:
public class House
{
public int Id { get; set; }
public int BedroomCount { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string StreetName { get; set; }
public string StreetNumber { get; set; }
}
And this fluent configuration:
modelBuilder.Entity<House>()
.HasOne(x => x.Address)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
Which leads to this DB configuration:
CREATE TABLE [House] (
[Id] int NOT NULL IDENTITY,
[AddressId] int,
[BedroomCount] int NOT NULL,
CONSTRAINT [PK_House] PRIMARY KEY ([Id]),
CONSTRAINT [FK_House_Address_AddressId] FOREIGN KEY ([AddressId]) REFERENCES [Address] ([Id]) ON DELETE CASCADE);
CREATE TABLE [Address] (
[Id] int NOT NULL IDENTITY,
[StreetName] nvarchar(max),
[StreetNumber] nvarchar(max),
CONSTRAINT [PK_Address] PRIMARY KEY ([Id]));
How do I specify a column name other than "AddressId" on the House table? I cannot find a method similar to HasColumnName like there is on non-navigation properties.
I'm using Entity Framework 7 RC1-Final.
You can use Data Annotations to configure the foreign key of your relationship.
public int AddressID { get; set; }
[ForeignKey("AddressID")]
public Address Address { get; set; }
This requires a property that will be used as the foreign key in your relationship. Also, note that it is recommended that you have a explicit foreign key for your relationships other than a shadow foreign key. This will prevent you to have a lot of problems when inserting/updating since you don't need to set the entire navigation property Address to save a House entity. See the problem here
Not tested but perhaps this could work (can't find a way to install EF7 right now)
modelBuilder.Entity<House>()
.HasOne(x => x.Address)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
.HasForeignKey(x => x.AddressID);
You can check here for more examples: Foreign Key Relationships EF7
You can get property first from modelBuilder.Entity<House>().Metadata.GetProperties() list and then set its name
property.Relational().ColumnName = "YouCustomId"
I have the following table in my database
Company
resourceId (uniqueidentifier)
name (nvarchar(50))
I have the following User entity in my application
public class ApplicationUser : IdentityUser
{
public String FirstName { get; set; }
public String Surname { get; set; }
public Guid CompanyId { get; set; }
}
and a configuration class
public class ApplicationUserMap : EntityTypeConfiguration<ApplicationUser>
{
public ApplicationUserMap()
{
}
}
Using fluentapi how can I map a foriegn key from CompanyId in Application user to my existing table resourceid?
You cannot do that if Company is not included in your model.
You can only create the relationship in the DB using an standard T-SQL sentence, in the DB initialization (Seed()) or in a customized migration (if you're using migrations).
The command would loook like this:
alter table ApplicationUser
add constraint App_Company_FK FOREIGN KEY (CompanyId) references Company(CompanyId)
To run it in the Seed method, override the inhertied Seed() method, and use any of the overloads of Database.ExecuteSqlCommand:
context.Database.ExecuteSqlCommand( ... );
I have a table used to store several inherited entities in TPH configuration.
That works well and there are no issues over that.
The issue I'm facing is that I need to extend some of those entities with additional fields and want those new fields stored in its own table using TPT.
To put some context I will give you an example:
The TPH stores a root PERIOD class and several inherited ones like QUARTER, MONTH, WEEK, etc, using a discriminator field.
So now I need to create a special QUARTER with some additional fields and want to store those additional field in its own table.
Is that possible in EF? I'm using EF 6.1 and haven't found a working sample or explanation on how to accomplish this specific scenario.
Thanks in advance,
Andrés.
public abstract class Period
{
public int Id { get; set; }
public string DisplayName { get; set; }
}
public class Month : Period {
public byte MonthValue { get; set; }
}
public class Quarter : Period {
public byte QuarterValue { get; set; }
}
public class SpecialQuarter : Quarter {
public int SpecialQuarterValue { get; set; }
}
public class TestContext : DbContext {
public DbSet<Period> Periods { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Period>().ToTable("Period");
// TPH
modelBuilder.Entity<Month>().Map(p => p.Requires("PeriodType").HasValue("M"));
modelBuilder.Entity<Quarter>().Map(p => p.Requires("PeriodType").HasValue("Q"));
//TPT
modelBuilder.Entity<SpecialQuarter>().Map(p => p.ToTable("SpecialQuarter"));
}
}
This context maps to these tables.
CREATE TABLE [dbo].[Period] (
[Id] [int] NOT NULL IDENTITY,
[DisplayName] [nvarchar](max),
[MonthValue] [tinyint],
[QuarterValue] [tinyint],
[PeriodType] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_dbo.Period] PRIMARY KEY ([Id])
)
CREATE TABLE [dbo].[SpecialQuarter] (
[Id] [int] NOT NULL,
[SpecialQuarterValue] [int] NOT NULL,
CONSTRAINT [PK_dbo.SpecialQuarter] PRIMARY KEY ([Id])
)
I'm using Code First CTP 5. I have a fairly simple setup between a parent table and child tables
Create table testA (
id int not null identity(1,1),
stuff varchar(200),
primary key (id)
);
go
create table testB (
id int not null
foreign key references testA(id),
morestuff varchar(200),
primary key (id)
);
go
To refer to these table using Code First, we have the following construct:
namespace Test.Models
{
public class TestEntities : DbContext
{
public DbSet<testa> testa { get; set; }
public DbSet<testb> testb { get; set; }
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<testa>().ToTable("testa");
modelBuilder.Entity<testa>()
.Property(p => p.id)
.HasDatabaseGenerationOption(DatabaseGenerationOption.Identity);
modelBuilder.Entity<testb>().ToTable("testb");
}
}
public class testa
{
public int id { get; set; }
public String stuff { get; set; }
public virtual testb testb { get; set; }
}
public class testb
{
public int id { get; set; }
public string morestuff { get; set; }
public virtual testa testa { get; set; }
}
}
When I try to add a record to testa, I get the error "Cannot insert explicit value for identity column in table 'testA' when IDENTITY_INSERT is set to OFF."
Ok. Strike 1 to Code First for not recognizing that Id is an identity column. We can fix this, so we tell CodeFirst that testa.id is an identity:
modelBuilder.Entity<testa>()
.Property(p => p.id)
.HasDatabaseGenerationOption(DatabaseGenerationOption.Identity);
That done we run it again and get another error: "A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'id'". So - what's wrong with this picture?
What am I doing wrong and how do I fix it???
In a 1:1 association, Code First recognize one of the entities as principal and the other one as dependent. Then it makes the principal PK as identity and you need to take care of a valid unique PK when inserting into the dependent table. In your case it picks testb as the principal but it looks like that you want testa to be the principal end in this association. This could be achieved by using fluent API and basically giving hint to Code First about which one is principal and which one is dependent:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<testb>()
.HasRequired(b => b.testa)
.WithOptional(a => a.testb);
}
For more information, take a look at this article:
Associations in EF Code First CTP5: Part 2 – Shared Primary Key Associations