-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fluent Api triggers table creation of base classes #10417
Comments
@JimBobSquarePants Using the Something like this can be used to bulk-configure all entity types that inherit from a type: foreach (var entityType in modelBuilder.Model.GetEntityTypes()
.Where(e => typeof(Entity).IsAssignableFrom(e.ClrType)))
{
modelBuilder
.Entity(entityType.ClrType)
.Property(nameof(Entity.Id))
.HasDefaultValueSql(SequentialGuid);
} Issues #9117 and #6787 are about making this somewhat easier. Also note that Id will be mapped as the key by convention, so it doesn't need to be mapped explicitly. HasAlternateKey is unlikely to be useful--see discussion here: #8645 Finally, I'm curious where your "understanding that abstract classes do not trigger table behaviour" comes from? I'm asking in case we need to update docs anywhere. |
Edit : After applying a migration, your code works partially. However, it creates static default values in the I have a similar problem regarding this issue. I have a base type that will not be mapped seperately to the database, but which contains some fields that I want to be present in all of my entities. And I want EF to automatically populate those fields. Here is the base class that I have : public abstract class EntityBase
{
public int Id { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedAt { get; set; }
public int CreatedBy { get; set; }
} Here is one of my entities that will be mapped to database : public class Bill : EntityBase
{
public DateTime DateTime { get; set; }
public double Total { get; set; }
} I have tried the following to populate fields, but it fails stating EntityBase is not present in database. modelBuilder.Entity<EntityBase>()
.Property(x => x.CreatedBy)
.ValueGeneratedOnAdd()
.HasDefaultValue(UserId); From your answer, I have tried the following. It works without an error, but the field is not populated in the database (It still has the default int value 0). foreach (var entityType in modelBuilder.Model.GetEntityTypes()
.Where(e => typeof(EntityBase).IsAssignableFrom(e.ClrType)))
{
modelBuilder
.Entity(entityType.ClrType)
.Property(nameof(EntityBase.CreatedBy))
.ValueGeneratedOnAdd()
.HasDefaultValue(5);
} I am using : |
@akyildizfirat I ran your code and it works fine for me. Can you please post a new issue with a runnable project/solution or code listing that demonstrates what you are seeing? Here's my little test listing using your code for reference: public abstract class EntityBase
{
public int Id { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedAt { get; set; }
public int CreatedBy { get; set; }
}
public class Bill : EntityBase
{
public DateTime DateTime { get; set; }
public double Total { get; set; }
}
public class TestDbContext : DbContext
{
public DbSet<Bill> Bills { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes()
.Where(e => typeof(EntityBase).IsAssignableFrom(e.ClrType)))
{
modelBuilder
.Entity(entityType.ClrType)
.Property(nameof(EntityBase.CreatedBy))
.ValueGeneratedOnAdd()
.HasDefaultValue(5);
}
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");
}
public class Program
{
public static void Main()
{
using (var context = new TestDbContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.Add(new Bill());
context.SaveChanges();
}
using (var context = new TestDbContext())
{
Console.WriteLine(context.Bills.Single().CreatedBy);
}
}
} |
I am sorry for the late reply and the confusion. I should have made a new post without editing my previous one. Let me try to be more specific. I have an abstract base class and many models inheriting from it. In the database, I want to have tables for concrete types. In addition, I am trying to make EF automatically populate the fields of the base class for each model for any query that I execute, if that is possible.
To be clear, I want a different UserId value inserted on each query at the runtime, depending on the value I get at the DbContext's constructor. Thank you. |
@akyildizfirat There isn't anything built-in to do that. I suspect you will be able to do with state-changing events, which is being tracked by issue #626 |
Thank you very much for your answers. |
If I attempt to configure primary key behaviour against base classes using the fluent API only those classes are created against the database. This behaviour is contrary to my understanding that abstract classes do not trigger table behaviour.
Steps to reproduce
Given the following base classes
And configuration code to normalize behaviour across my concrete types
The library will create two tables in my database
Entity
andRangeEntity
. These tables contain some of the properties of inheriting classes and foreign keys for inheriting classes also. No other tables are generated. I have configuredDbSet
roperties for all my concrete types.I would expect EF Core to create tables and implement those rules for all inheriting concrete types and not create tables for the base types.
Further technical details
EF Core version:
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: Visual Studio 2017
The text was updated successfully, but these errors were encountered: