从EF 4升级到6,类继承和Discriminator

时间:2016-01-26 12:27:20

标签: c# entity-framework inheritance

我有一个EF 4解决方案,我试图转移到更新的EF(和.net) 我已经升级了EF并修复了所有项目,因此处理了EF 6和新的目标平台。 问题是EF4和6以不同的方式处理db中的类继承。我有一个继承User类的BackendUser类。在db中,BackendUser表将具有BackendUser属性和将获得用户属性的UserId

升级时,EF尝试从User表中获取所有数据,并使用Discriminator属性来处理类。

我猜我必须将db转换为新方式或设置EF来处理继承" old"办法。我还猜测新的方式可能会有更好的表现吗?

是否有任何最佳实践如何处理此问题以获得新的数据库结构的旧解决方案,还是我看着手动更新数据库的时间?

编辑:找到有关TPT和添加课程的更多信息,因此我猜测EF不会出于某种原因处理表格属性? (遗漏了一些道具)

[Table("ResellerContact")]
public class ResellerContact : BackendUser
{        
    public string ResellerName {get; set; }
}

[Table("BackendUser")]
public class BackendUser : User
{
    public bool IsSystemOwner { get; set;}     
}

public abstract class User 
{
    public long UserId { get; set; }

    [Required(ErrorMessage = "*")]
    [StringLength(15, ErrorMessageResourceName = "UsernameValidationMessage", ErrorMessageResourceType = typeof(UserResource))]
    [Display(Name = "Username", ResourceType = typeof(ResellerContactResource))]
    public string UserName { get; set;}
}

获取后端用户结果以下sql

SELECT TOP (2) 
[Extent1].[Discriminator] AS [Discriminator], 
[Extent1].[UserId] AS [UserId], 
[Extent1].[UserName] AS [UserName], 
[Extent1].[Email] AS [Email], 
[Extent1].[Password] AS [Password], 
[Extent1].[RoleId] AS [RoleId], 
[Extent1].[IsSystemOwner] AS [IsSystemOwner], 
[Extent1].[FullName] AS [FullName], 
[Extent1].[Phone1] AS [Phone1], 
[Extent1].[Mobile1] AS [Mobile1], 
[Extent1].[ResellerContactType] AS [ResellerContactType], 
[Extent1].[Language1] AS [Language1], 
[Extent1].[ResellerId] AS [ResellerId], 
[Extent1].[IsActive1] AS [IsActive1]
FROM [dbo].[User] AS [Extent1]
WHERE ([Extent1].[Discriminator] IN (N'ResellerContact',N'BackendUser')) AND ([Extent1].[UserName] = @p__linq__0) AND ([Extent1].[Password] = @p__linq__1)

2 个答案:

答案 0 :(得分:0)

我已经进行了一些测试,这应该可以使用Table属性

public class FooContext : DbContext
{
   public DbSet<User> Users { get; set; }
   public DbSet<BackendUser> BackendUsers { get; set; }
   public DbSet<ResellerContact> ResellerContacts { get; set; }
}

这是生成的迁移代码,它是TPT并且应该与您的数据库匹配:

CreateTable(
    "dbo.Users",
    c => new
        {
            UserId = c.Long(nullable: false, identity: true),
            UserName = c.String(),
        })
    .PrimaryKey(t => t.UserId);

CreateTable(
    "dbo.BackendUser",
    c => new
        {
            UserId = c.Long(nullable: false),
            IsSystemOwner = c.Boolean(nullable: false),
        })
    .PrimaryKey(t => t.UserId)
    .ForeignKey("dbo.Users", t => t.UserId)
    .Index(t => t.UserId);

CreateTable(
    "dbo.ResellerContact",
    c => new
        {
            UserId = c.Long(nullable: false),
            ResellerName = c.String(),
        })
    .PrimaryKey(t => t.UserId)
    .ForeignKey("dbo.BackendUser", t => t.UserId)
    .Index(t => t.UserId);

答案 1 :(得分:0)

解决了问题,它是实体框架版本。

我已更新实体框架,解决了一些有关System.ComponentModel.DataAnnotations(与其他人)的参考问题,然后将taget版本更改为.Net 4.6

然后,我发现链接表明实体框架需要重新安装新目标,并且没有从所有项目中删除。因此,当我安装它时,它会继续安装.Net 4.0

因此,在所有项目上卸载Entity Framework,再次添加它以使目标正确并且[Table]仍然有效。我猜测注释属性来自错误的库,而不是由实体框架正确处理。

参考:Can I implement Entity Framework 5 TPT on Windows XP?

TPT仍然是性能问题(https://msdn.microsoft.com/en-US/data/hh949853中的第7.2节),我将尝试将其更改为TPH。为了解决这个问题,我发现我将为当前的db创建一个迁移,然后重新编译这些类以获取迁移脚本如何更新表。 这个帖子向我指出了这个方向 Entity Framework Code First Convert TPT to TPH

感谢@Jcl的输入