Open phiree opened 1 year ago
@phiree Your example code uses fields instead of properties. EF Core doesn't map fields by default.
i have updated example code.
@phiree I am not able to reproduce this; see my code below. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.
using (var context = new SomeDbContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
}
public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))
.UseLazyLoadingProxies()
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>();
modelBuilder.Entity<BaseOrder>();
modelBuilder.Entity<SaleOrder>();
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
// base order has a product
public class BaseOrder
{
public int Id { get; set; }
public virtual Product Product { get; set; }
}
// saleorder inherits from BaseOrder
public class SaleOrder : BaseOrder
{
public Seller Seller { get; set; }
}
public class Seller
{
public int Id { get; set; }
}
@ajcvickers thanks for your attension . after checking your code , i found i missed a important point in my post : base class is abstract . i will edit it later. you can change BaseOrder to abstract and try again, or use the runable code below( .net 7 console app, dependencies: Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.InMemory Microsoft.EntityFrameworkCore.Proxies )
using Microsoft.EntityFrameworkCore;
namespace efcore_virtual_base_not_throw
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(@"
Situation:
1) base class(Order) is abstract, it has a **no-virtual** property:Product
2) SaleOrder inherits from Order
3) enbale lazy loading
Problem:
when i retrive a SaleOrder from database
1)no exception throw
2) saleOrder.Product is null
Expect:
thrown InvalidOperationException( System.InvalidOperationException:“Property 'SaleOrder.Product' is not virtual. 'UseChangeTrackingProxies' requires all entity............. )
,to remind me add virtual to Product .
");
Save();
Get();
}
static void Save()
{
using (var context = new SomeDbContext())
{
context.Database.EnsureDeletedAsync();
context.Database.EnsureCreatedAsync();
var product1 = new Product { Name = "P1", Id = 1 };
var product2 = new Product { Name = "P2", Id = 2 };
context.Add<SaleOrder>(new SaleOrder { Id = 2, ProductWithoutVirtual = product1, ProductWithVirtual=product2 });
context.SaveChanges();
}
}
static void Get()
{
using (var context = new SomeDbContext())
{
var order = context.Set<SaleOrder>().Find(2);
Console.WriteLine("-------------code result ------------------" );
Console.WriteLine("Product with virtual is lazy loaded, its name is :" + order.ProductWithVirtual.Name);
Console.WriteLine("Product without virtual: is null, and no exception thrown. " + (order.ProductWithoutVirtual==null?"it is null!": order.ProductWithoutVirtual.Name));
Console.Read();
}
}
}
public class SomeDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<SaleOrder> SaleOrders { get; set; }
public DbSet<BaseOrder> BaseOrders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseInMemoryDatabase("db")//(connectionString, ServerVersion.AutoDetect(connectionString))
.UseLazyLoadingProxies()
// .LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>();
// modelBuilder.Entity<BaseOrder>();
modelBuilder.Entity<SaleOrder>();
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
// abstract base class, has a product
public abstract class BaseOrder
{
public int Id { get; set; }
public virtual Product ProductWithVirtual { get; set; }
public Product ProductWithoutVirtual { get; set; }
}
// saleorder inherits from BaseOrder
public class SaleOrder : BaseOrder
{
}
}
Note for triage: I am now able to reproduce this. Seems to be dependent on entity type discovery order.
code
Problem
no exception thown , but set saleOrder.Product to null instead. if i remove "virtual" of Seller( direct property of saleorder), a runtime error will be thorwn.
why efcore didn't check "virtual " modifier of base class's property?
Expect
throw Exception like this:
Include provider and version information
EF Core version: Database provider:Pomelo.EntityFrameworkCore.MySql Target framework: (e.g. .NET 7.0) Operating system: IDE: Visual Studio 2022 17.6.2