deleted child entity generate wrong query? - entity-framework

the following code
using System;
using System.Linq;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data.Entity.ModelConfiguration;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Data.SqlClient;
using System.Reflection;
namespace testef {
public class Order {
public Int32 Id { get; set; }
public String O { get; set; }
public virtual ICollection<OrderDetail> Details { get; set; }
}
public class OrderDetail {
public virtual Order Order { get; set; }
public Int32 Id { get; set; }
public String D { get; set; }
public Boolean IsActive { get; set; }
}
public class OrderDetailConfiguration : EntityTypeConfiguration<OrderDetail> {
public OrderDetailConfiguration()
: base() {
HasRequired(d => d.Order).WithMany(o => o.Details);
}
}
public class TestEFContext : DbContext {
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> Details { get; set; }
public TestEFContext(String cs)
: base(cs) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
//Database.SetInitializer<TestEFContext>(null);
//Database.SetInitializer<TestEFContext>(new CreateDatabaseIfNotExists<TestEFContext>());
//Database.SetInitializer<TestEFContext>(new CustomDataBaseInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new OrderDetailConfiguration());
}
}
public class CustomDataBaseInitializer : CreateDatabaseIfNotExists<TestEFContext> {
public CustomDataBaseInitializer() : base() {
}
}
class Program {
static void Main(string[] args) {
String cs = #"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext ctx = new TestEFContext(cs)) {
Order o = new Order {
O = "O1",
Details = new List<OrderDetail>{
new OrderDetail { D = "D11", IsActive = true},
new OrderDetail { D = "D12", IsActive = false}
}
};
ctx.Orders.Add(o);
ctx.SaveChanges();
}
using (TestEFContext ctx = new TestEFContext(cs)) {
//OrderDetail d = new OrderDetail { Id = 1};
//ctx.Details.Attach(d);
OrderDetail d = ctx.Details.Where(x => x.Id == 1).First();
ctx.Details.Remove(d);
ctx.SaveChanges();
// ==> exec sp_executesql N'DELETE [dbo].[OrderDetails] WHERE (([Id] = #0) AND ([Order_Id] = #1))',N'#0 int,#1 int',#0=1,#1=1
}
}
}
}
generate following sql:
exec sp_executesql N'DELETE [dbo].[OrderDetails] WHERE (([Id] = #0) AND ([Order_Id] = #1))',N'#0 int,#1 int',#0=1,#1=1
I can't figure out why AND ([Order_Id] = #1. For me as the PK is Id a WHERE on Id must be enough!
Where am I wrong ?

It's a design decision the team made. I wouldn't consider either your stance or the EF teams tactic wrong...just choices. Both have benefits. I wouldn't get hung up on it, partially because deleting is uncommon in most applications, partially because there's an easy work around if performance is an issue.
If you want to execute just one query, do something like this:
ctx.Database.ExecuteSqlCommand("delete from [dbo].[OrderDetails] where Id = #p0", 1);

Related

How to declare a parent child relationship when both tables are TPH and the relationship is in the base classes?

My problem relates to sales orders and sales invoices but I find it easier to think of pets and their offspring... without creating a full pedigree model.
My DbContext
using System;
using DevExpress.ExpressApp.EFCore.Updating;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy;
using DevExpress.Persistent.BaseImpl.EF;
using DevExpress.ExpressApp.Design;
using DevExpress.ExpressApp.EFCore.DesignTime;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using DevExpress.ExpressApp.DC;
using System.Collections.Generic;
namespace Pets.Module.BusinessObjects
{
[TypesInfoInitializer(typeof(PetsContextInitializer))]
public class PetsEFCoreDbContext : DbContext
{
public PetsEFCoreDbContext(DbContextOptions<PetsEFCoreDbContext> options) : base(options)
{
}
public DbSet<Cat> Cats { get; set; }
public DbSet<Dog> Dogs { get; set; }
public DbSet<Kitten> Kittens { get; set; }
public DbSet<Puppy> Puppys { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Pet>()
.HasDiscriminator(x=> x.IsCat)
.HasValue<Cat>(true)
.HasValue<Dog>(false);
modelBuilder.Entity<BabyPet>()
.HasDiscriminator(x => x.IsCat)
.HasValue<Kitten>(true)
.HasValue<Puppy>(false);
modelBuilder.Entity<Puppy>().HasOne(x => x.Parent).WithMany(x => x.Puppies);
modelBuilder.Entity<Kitten>().HasOne(x => x.Parent).WithMany(x => x.Kittens);
}
}
}
My classes
public abstract class Pet
{
[Key] public int Id { get; set; }
public string Name { get; set; }
public bool? IsCat { get; set; }
}
public abstract class BabyPet
{
[Key] public int Id { get; set; }
public int ParentPetId { get; set; }
[ForeignKey("ParentPetId")]
public virtual Pet Parent { get; set; }
public string Name { get; set; }
public bool? IsCat { get; set; }
}
public class Kitten : BabyPet
{
new public virtual Cat Parent { get; set; }
}
public class Dog : Pet
{
public Dog()
{
Puppies = new List<Puppy>();
}
[Aggregated]
public virtual List<Puppy> Puppies { get; set; }
}
public class Cat : Pet
{
public Cat()
{
Kittens = new List<Kitten>();
}
[Aggregated]
public virtual List<Kitten> Kittens { get; set; }
}
public class Puppy : BabyPet
{
new public virtual Dog Parent { get; set; }
}
Also there is
public class PetsContextInitializer : DbContextTypesInfoInitializerBase
{
protected override DbContext CreateDbContext()
{
var optionsBuilder = new DbContextOptionsBuilder<PetsEFCoreDbContext>()
.UseSqlServer(#";");
return new PetsEFCoreDbContext(optionsBuilder.Options);
}
}
However this creates the following structure in BabyPet
Where as I just want
[Update]
I was able to get the structure I want by specifying the foreignkey in OnModelCreating
modelBuilder.Entity<Puppy>().HasOne(x => x.Parent).WithMany(x => x.Puppies).HasForeignKey(x=>x.ParentPetId);
modelBuilder.Entity<Kitten>().HasOne(x => x.Parent).WithMany(x => x.Kittens).HasForeignKey(x => x.ParentPetId);
However when I try to add a Kitten to a cat via the XAF Winforms UI I get:
Unable to cast object of type 'SimplePets.Module.BusinessObjects.Kitten' to type 'SimplePets.Module.BusinessObjects.Puppy'.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.get_Item(IPropertyBase propertyBase)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.GetCurrentValue(IPropertyBase propertyBase)
at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.TryAddPropertyNameToCollection(InternalEntityEntry entity, ICollection`1 propertiesToCheck, IPropertyBase property)
at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.TryAddPropertyNameToCollection(InternalEntityEntry entity, IProperty property, ICollection`1 propertiesToCheck)
at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.GetPropertiesToCheck(InternalEntityEntry entity)
at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.CheckReadWritePermissionsForNonIntermediateObject(InternalEntityEntry entity)
at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.CheckReadWritePermissions(InternalEntityEntry entity)
at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.CheckIsGrantedToSave(InternalEntityEntry entity)
at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.GetEntriesToSave(Boolean cascadeChanges)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(DbContext _, Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
at DevExpress.ExpressApp.EFCore.EFCoreObjectSpace.DoCommit()
at DevExpress.ExpressApp.BaseObjectSpace.CommitChanges()
at DevExpress.ExpressApp.Win.SystemModule.WinModificationsController.Save(SimpleActionExecuteEventArgs args)
at DevExpress.ExpressApp.SystemModule.ModificationsController.saveAction_OnExecute(Object sender, SimpleActionExecuteEventArgs e)
at DevExpress.ExpressApp.Actions.SimpleAction.RaiseExecute(ActionBaseEventArgs eventArgs)
at DevExpress.ExpressApp.Actions.ActionBase.ExecuteCore(Delegate handler, ActionBaseEventArgs eventArgs)
I put my example on GitHub here
Docs link about relationships here and tph inheritance is here
I think I must have the data structures correct after my update to onModelCreating. That is :
modelBuilder.Entity<Puppy>().HasOne(x => x.Parent).WithMany(x => x.Puppies).HasForeignKey(x=>x.ParentPetId);
modelBuilder.Entity<Kitten>().HasOne(x => x.Parent).WithMany(x => x.Kittens).HasForeignKey(x => x.ParentPetId);
I was able to work around the Cast Object error by using DBContext instead of ObjectSpace
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using SimplePets.Module.BusinessObjects;
using System.Linq;
namespace SimplePets.Module.Win.Controllers
{
public class KittenViewController : ViewController
{
SimpleAction actionAddKittenEF;
SimpleAction actAddKittenXAF;
public KittenViewController() : base()
{
TargetObjectType = typeof(Kitten);
TargetViewNesting = Nesting.Nested;
actAddKittenXAF = new SimpleAction(this, "Add via OS", "View");
actAddKittenXAF.Execute += actAddKittenXAF_Execute;
actionAddKittenEF = new SimpleAction(this, "Add via Db", "View");
actionAddKittenEF.Execute += actionAddKittenEF_Execute;
}
private void actionAddKittenEF_Execute(object sender, SimpleActionExecuteEventArgs e)
{
var cat = View.ObjectSpace.GetObject(((NestedFrame)Frame).ViewItem.CurrentObject) as Cat;
var db = Helpers.MakeDb();
var kitten = new Kitten
{
Parent = db.Cats.FirstOrDefault(c => c.Id == cat.Id),
Name = $"baby {cat.Kittens.Count + 1} of {cat.Name}"
};
db.Kittens.Add(kitten);
db.SaveChanges();
View.ObjectSpace.Refresh();
}
//Errors
private void actAddKittenXAF_Execute(object sender, SimpleActionExecuteEventArgs e)
{
var cat = View.ObjectSpace.GetObject(((NestedFrame)Frame).ViewItem.CurrentObject) as Cat;
var os = View.ObjectSpace;
var kitten = os.CreateObject<Kitten>();
kitten.Parent = cat;
kitten.Name = $"baby {cat.Kittens.Count + 1} of {cat.Name}";
View.ObjectSpace.CommitChanges();
View.ObjectSpace.Refresh();
}
}
}

Entity Framework Core 2.0: Error when enumerating over query with group

I have the following method which simply iterates over orders grouped by client ID.
static void LinqWithInto()
{
using (var db = new EFContext())
{
var orders = db.Orders.Include(o => o.Client);
orders.Load();
var query = from order in orders
group order by order.ClientId into g
select new { ClientId = g.Key, Count = g.Count(), Orders = g };
foreach (var group in query)
{
WriteLine($"Client Id: {group.ClientId}, Number of orders: {group.Count}");
foreach (var order in group.Orders)
WriteLine($"\tOrder Id: {order.OrderId}, Client Id: {order.Client.ClientId}, Client Name: " +
$"{order.Client.Name} Payment: {order.Payment}");
}
}
}
The query fetches orders with associated clients:
[Table("Order")]
public class Order
{
public int OrderId { get; set; }
public int ClientId { get; set; }
public double Payment { get; set; }
[ForeignKey("ClientId")]
public Client Client { get; set; }
}
[Table("Client")]
public class Client
{
public int ClientId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public List<Order> Orders { get; set; }
}
The code works well in EF6, but in EF Core I get the following error (the variable query in foreach loop is highlighted):
System.ArgumentException: 'Expression of type 'System.Object' cannot be used for parameter of type 'Microsoft.EntityFrameworkCore.Metadata.IEntityType' of method 'Void StartTracking(System.Object, Microsoft.EntityFrameworkCore.Metadata.IEntityType)''
I wonder what's wrong here?
This seems to be a bug in EF Core 2.0 which got addressed in this issue (Contains workaround):
https://github.com/aspnet/EntityFrameworkCore/issues/9551
You can get the testfeed 2.0.3 here (Contains fix):
https://github.com/aspnet/Announcements/issues/274
Here is a repro (which you should post over at GitHub), and a workaround. As Ivan said, that code doesn't make much sense, as the grouping query will still be sent to the database.
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Collections.Generic;
namespace efCoreTest
{
[Table("Order")]
public class Order
{
public int OrderId { get; set; }
public int ClientId { get; set; }
public double Payment { get; set; }
[ForeignKey("ClientId")]
public Client Client { get; set; }
}
[Table("Client")]
public class Client
{
public int ClientId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public List<Order> Orders { get; set; } = new List<Order>();
}
class Db : DbContext
{
public DbSet<Client> Clients { get; set; }
public DbSet<Order> Orders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=.;Database=efCoreTest;Integrated Security=true");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
class Program
{
static void Main(string[] args)
{
using (var db = new Db())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
for (int i = 0; i < 10; i++)
{
var client = new Client() { Address = "Address", Name = $"Client{i}" };
db.Clients.Add(client);
for (int j = 0; j < 5; j++)
{
var order = new Order() { Client = client, Payment = 20 };
db.Orders.Add(order);
}
}
db.SaveChanges();
}
using (var db = new Db())
{
//works
var orders = db.Orders.Include(o => o.Client).ToList() ;
//fails
//var orders = db.Orders.Include(o => o.Client);
// orders.Load();
var query = from order in orders
group order by order.ClientId into g
select new { ClientId = g.Key, Count = g.Count(), Orders = g };
foreach (var group in query)
{
Console.WriteLine($"Client Id: {group.ClientId}, Number of orders: {group.Count}");
foreach (var order in group.Orders)
Console.WriteLine($"\tOrder Id: {order.OrderId}, Client Id: {order.Client.ClientId}, Client Name: " +
$"{order.Client.Name} Payment: {order.Payment}");
}
Console.WriteLine("Complete");
Console.ReadKey();
}
}
}
}

How to use Include method in LINQ To Entity when not sure that it has the specified navigation property?

I give you a CF example:
public class MyContext : DbContext
{
public DbSet<A> A { get; set; }
}
public class A
{
public int E { set; get; }
}
public class B : A
{
public int F { set; get; }
}
public class C : A
{
public int G { set; get; }
public virtual D D { set; get; }
}
public class D { }
and the query is like this:
using (var context = new MyContext())
{
var queryResult = context.A.Include("D").Select(a => a);
}
and it throws an exception with this message:
A specified Include path is not valid. The EntityType 'A' does not
declare a navigation property with the name 'D'.
How would you solve this with only one LINQ To Entity query?
Here is a work around
using (var context = new MyContext())
{
var typeA=typeOf(A);
var queryResult ;
if( typeA.GetProperty("D")!=null)
queryResult = context.A.Include("D").Select(a => a);
}

EF query not returning foreign key value of navigation property

I'm using EF5 Code First and Lazy Loading is disabled. I have the following code:
//Model
public class Task
{
public Guid Id {get; set;}
//other properties that are not relevant here
public Guid CreatorId {get; set;}
public User Creator {get; set;}
public Guid? OwnerId {get; set;}
public User Owner {get; set;}
}
//Model
public class User
{
public Guid Id { get; set; }
//other properties that are not relevant here
public string UserName { get; set; }
public IList<Task> TasksCreated { get; set; }
public IList<Task> TasksOwned { get; set; }
}
//Configuration for Task
public class TaskConfiguration : EntityTypeConfiguration<Task>
{
public TaskConfiguration()
{
HasRequired(task => task.Creator)
.WithMany(creator => creator.TasksCreated)
.HasForeignKey(task => task.CreatorId)
.WillCascadeOnDelete(false);
HasOptional(task => task.Owner)
.WithMany(owner => owner.TasksOwned)
.HasForeignKey(task => task.OwnerId)
.WillCascadeOnDelete(false);
}
}
When I query against Tasks, all the data comes back as expected. When I query against Users using the following query, the Tasks property for Owner or Creator is null. The null value is assigned to whatever property does not match the User I am querying for. So, if User2 is the Owner on User1's Task, User2's ID will come back, but the Owner property will be null. This is the query:
var db = new MyContext();
var user = db.Users
.Include("TasksCreated")
.Include("TasksOwned")
.SingleOrDefault(u => u.UserName.Equals("user1", StringComparison.OrdinalIgnoreCase));
I'm not sure if there is another step I'm missing or if I don't have the proper configuration for the Task-User relationship. Any help is appreciated.
i try your code and it runs.
The only difference is the constructor of the context I add:
public class TestEFContext : DbContext {
public IDbSet<User> us { get; set; }
public IDbSet<Task> ts { get; set; }
public TestEFContext(String cs)
: base(cs) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
Configuration.LazyLoadingEnabled = false;
modelBuilder.Configurations.Add(new TaskConfiguration());
}
}
from here the following :
class Program {
static void Main(String[] args) {
String cs = #"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext c = new TestEFContext(cs)) {
User u1 = new User {
Id = Guid.NewGuid(),
UserName = "u1"
};
User u2 = new User {
Id = Guid.NewGuid(),
UserName = "u2"
};
c.us.Add(u1);
c.us.Add(u2);
Task t = new Task {
Id = Guid.NewGuid(),
Creator = u1,
Owner = u1
};
c.ts.Add(t);
t = new Task {
Id = Guid.NewGuid(),
Creator = u2,
Owner = u1
};
c.ts.Add(t);
c.SaveChanges();
}
using (TestEFContext c = new TestEFContext(cs)) {
var user = c.us
.Include("TasksCreated")
.Include("TasksOwned")
.SingleOrDefault(u => u.UserName.Equals("u1", StringComparison.OrdinalIgnoreCase));
foreach (Task t in user.TasksCreated) {
Console.WriteLine(t.Id);
}
Console.WriteLine("-----");
foreach (Task t in user.TasksOwned) {
Console.WriteLine(t.Id);
}
}
}
}
displays as expected:
a415c8c6-6b0a-4e1b-a42f-cd4230cf4d4a
-----
a415c8c6-6b0a-4e1b-a42f-cd4230cf4d4a
a2e9c527-d8cb-4db7-8879-7febb1c30a07
Appuyez sur une touche pour continuer...
EDITION ========== ==========
the following code runs also:
using System;
using System.Linq;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data.Entity.ModelConfiguration;
namespace testef {
//Model
public class Task {
public Guid Id { get; set; }
//other properties that are not relevant here
public String ShortDescription { get; set; }
public Guid CreatorId { get; set; }
public User Creator { get; set; }
public Guid? OwnerId { get; set; }
public User Owner { get; set; }
}
//Model
public class User {
public Guid Id { get; set; }
//other properties that are not relevant here
public string UserName { get; set; }
public IList<Task> TasksCreated { get; set; }
public IList<Task> TasksOwned { get; set; }
}
//Configuration for Task
public class TaskConfiguration : EntityTypeConfiguration<Task> {
public TaskConfiguration() {
HasRequired(task => task.Creator)
.WithMany(creator => creator.TasksCreated)
.HasForeignKey(task => task.CreatorId)
.WillCascadeOnDelete(false);
HasOptional(task => task.Owner)
.WithMany(owner => owner.TasksOwned)
.HasForeignKey(task => task.OwnerId)
.WillCascadeOnDelete(false);
}
}
public class TestEFContext : DbContext {
public IDbSet<User> us { get; set; }
public IDbSet<Task> ts { get; set; }
public TestEFContext(String cs)
: base(cs) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
Configuration.LazyLoadingEnabled = false;
modelBuilder.Configurations.Add(new TaskConfiguration());
}
}
class Program {
static void Main(String[] args) {
String cs = #"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext c = new TestEFContext(cs)) {
User u1 = new User {
Id = Guid.NewGuid(),
UserName = "u1"
};
User u2 = new User {
Id = Guid.NewGuid(),
UserName = "u2"
};
c.us.Add(u1);
c.us.Add(u2);
Task t = new Task {
Id = Guid.NewGuid(),
ShortDescription = "t1",
Creator = u1,
Owner = u1
};
c.ts.Add(t);
t = new Task {
Id = Guid.NewGuid(),
ShortDescription = "t2",
Creator = u2,
Owner = u1
};
c.ts.Add(t);
c.SaveChanges();
}
using (TestEFContext c = new TestEFContext(cs)) {
var user = c.us
.Include("TasksCreated")
.Include("TasksOwned")
.SingleOrDefault(u => u.UserName.Equals("u1", StringComparison.OrdinalIgnoreCase));
foreach (Task t in user.TasksCreated) {
Console.WriteLine("{0} - {1} is owned by {2}, was created by {3} ", t.ShortDescription, t.Id, t.OwnerId, t.CreatorId);
}
Console.WriteLine("-----");
foreach (Task t in user.TasksOwned) {
Console.WriteLine("{0} - {1} is owned by {2}, was created by {3} ", t.ShortDescription, t.Id, t.OwnerId, t.CreatorId);
}
}
}
}
}

TPC mappint generate the base class table

I want to achieve TPC mapping by code-first, and I have read this article:
Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC)
I've wrote the code as below.
namespace TPCTest
{
class Program
{
static void Main(string[] args)
{
using (TestContext context = new TestContext())
{
Manager m = new Manager();
m.AnnualSalary = 100000;
m.Name = "Allen";
m.Sex = true;
m.Id = 1;
Worker w = new Worker();
w.Id = 2;
w.Name = "John";
w.Sex = true;
w.MonthlyPay = 5000;
context.empSet.Add(m);
context.empSet.Add(w);
context.SaveChanges();
}
}
}
abstract class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public bool Sex { get; set; }
}
class Manager : Employee
{
public decimal AnnualSalary { get; set; }
public string Department { get; set; }
}
class Worker : Employee
{
public decimal MonthlyPay { get; set; }
}
class TestContext : DbContext
{
public DbSet<Employee> empSet { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Manager>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Manager");
});
modelBuilder.Entity<Worker>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Worker");
});
modelBuilder.Entity<Employee>().Property(e => e.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None);
}
}
}
But after running the code, I found the Employee table also exist in database, anyone can help?
Thanks in advance!
Use EF 5.0 or higher!
The issue seems to be fixed since that version. With EF 4.3.1 I could reproduce the behavior. So just update.