我有一个具有抽象类型属性的实体。这将创建一个使用逐层表继承的一对一关系。一切似乎都正常工作。
我可以创建一个 Item 并将Base
属性设置为ConcreteOne
; 一切都正确保存。但是,当我尝试更新Base
到 时ConcreteTwo
,EFBase
使用新的用户值更新数据库中的记录,它不会更新类型的鉴别器。所以额外的数据ConcreteTwo
会被保留,但鉴别器仍然说ConcreteOne
.
下面是一个暴露问题的简单例子
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
App_Start.EntityFrameworkProfilerBootstrapper.PreStart();
Database.SetInitializer(new DropCreateDatabaseAlways<DataContext>());
// Create our item with ConcreteOne for Base
using (var context = new DataContext())
{
var item = new Item
{
Base = new ConcreteOne { Name = "Item", Data = 3 }
};
context.Items.Add(item);
context.SaveChanges();
}
// Update Base with a new ConcreteTwo
using (var context = new DataContext())
{
var item = context.Items.FirstOrDefault();
var newBase = new ConcreteTwo()
{
Item = item,
Name = "Item 3",
User = new User { Name = "Foo" }
};
// If I don't set this to null, EF tries to create a new record in the DB which causes a PK exception
item.Base.Item = null;
item.Base = newBase;
// EF doesn't save the discriminator, but DOES save the User reference
context.SaveChanges();
}
// Retrieve the item -- EF thinks Base is still ConcreteOne
using (var context = new DataContext())
{
var item = context.Items.FirstOrDefault();
Console.WriteLine("{0}: {1}", item.Name, item.Base.Name);
}
Console.WriteLine("Done.");
Console.ReadLine();
}
}
public class DataContext : DbContext
{
public DbSet<Item> Items { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Base Base { get; set; }
}
public abstract class Base
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public virtual Item Item { get; set; }
}
public class ConcreteOne : Base
{
public int Data { get; set; }
}
public class ConcreteTwo : Base
{
public virtual User User { get; set; }
}
}
保存更改后,EF 会生成以下 SQL:
update [dbo].[Bases]
set [Name] = 'Item 3' /* @0 */,
[User_Id] = 1 /* @1 */
where (([Id] = 1 /* @2 */)
and [User_Id] is null)
所以这几乎是正确的,但我希望[Discriminator] = 'ConcreteTwo'
在更新声明中看到。我的期望是没有根据的还是我做错了什么?
作为测试,我尝试使用 table-per-type 并且该条目已从表中删除并按我的预期ConcreteOne
添加到表中。ConcreteTwo
所以它可以工作,但是我的实际应用程序至少有七个子类型,并且用于检索Base
属性的 SQL 语句变得非常讨厌。因此,如果可能的话,我当然希望使用 TPH 来完成此任务。
更新: 我已验证 EF5 和 EF6 中都存在问题。