Previous non core version of Entity Framework had something like this:
modelBuilder.Type<IEntity>().HasKey(e => e.Id);
I'm curious if this is planned for core version to?
I tried to implement something similar with reflection. https://gist.github.com/matjazmav/2e7335c12c55c4f6692b637bccf651bb There is only one problem with this implementation, casting object to EntityModelBuilder<TEntity> (this is marked with // TODO in the gist snippet). Anyone wan't to help me solve this?
Thanks!
We don't have the equivalent functionality in EF Core yet, but you can write something like this (less pretty, but does the same thing).
c#
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes().Where(e => typeof(IEntity).IsAssignableFrom(e.ClrType)))
{
modelBuilder.Entity(entity.Name).HasKey(nameof(IEntity.Key));
}
}
Would also allow to use modelBuilder.Owned to bulk configure owned types.
Related to #3867
The workaround mentioned above doesn't seem to be working for inherited property definitions. I have the following statement in my OnModelCreating():
foreach (var entity in modelBuilder.Model.GetEntityTypes()
.Where(e => typeof(IEntity).IsAssignableFrom(e.ClrType)))
{
modelBuilder.Entity(entity.Name).Property(nameof(IEntity.Uuid))
.IsRequired().HasDefaultValueSql("NEWID()");
}
I'd expect this produce the following line in the migration for each IEntity, but it does not:
Uuid = table.Column<Guid>(nullable: false, defaultValueSql: "NEWID()")
@chrispickford It works for me in a simple test:
```C#
public interface IEntity
{
Guid Id { get; set; }
}
public class Vehicle : IEntity
{
public Guid Id { get; set; }
public string VehicleIdentificationNumber { get; set; }
}
public class VehiclePrototype : IEntity
{
public Guid Id { get; set; }
public DateTimeOffset? PressReleaseAt { get; set; }
}
public class BloggingContext : DbContext
{
private static readonly LoggerFactory Logger
= new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) });
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLoggerFactory(Logger)
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Vehicle>();
modelBuilder.Entity<VehiclePrototype>();
foreach (var entity in modelBuilder.Model.GetEntityTypes()
.Where(e => typeof(IEntity).IsAssignableFrom(e.ClrType)))
{
modelBuilder.Entity(entity.Name).Property(nameof(IEntity.Id))
.IsRequired().HasDefaultValueSql("NEWID()");
}
}
}
public class Program
{
public static async Task Main()
{
using (var context = new BloggingContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
context.Add(new Vehicle());
context.Add(new VehiclePrototype());
context.SaveChanges();
}
}
}
```
@ajcvickers Apologies, in my haste I constructed an incorrect example. The IEntity should be an abstract class, e.g:
public abstract class Entity
{
public int Id { get; set; }
public byte[] RowVersion { get; set; }
public Guid Uuid { get; set; }
}
@chrispickford Still works for me. Can you please file a new issue including a runnable project/solution or complete code listing that demonstrates the behavior you are seeing.
Consider also query filters--see #17434
Most helpful comment
We don't have the equivalent functionality in EF Core yet, but you can write something like this (less pretty, but does the same thing).
c# protected override void OnModelCreating(ModelBuilder modelBuilder) { foreach (var entity in modelBuilder.Model.GetEntityTypes().Where(e => typeof(IEntity).IsAssignableFrom(e.ClrType))) { modelBuilder.Entity(entity.Name).HasKey(nameof(IEntity.Key)); } }