【问题标题】:TPH Inheritance mapping uses nchar (N'value') instead of char ('value') for discriminator column valueTPH 继承映射使用 nchar (N'value') 而不是 char ('value') 作为鉴别器列值
【发布时间】:2012-08-09 15:06:42
【问题描述】:

我正在使用现有数据库并使用 EF 4.3 Code First。我有一个看起来像这样的实体层次结构,其中 Note 是基类:

Note
  - CompanyNote
  - OrderNote
  - etc

我将TPH 与具有以下映射的鉴别器列一起使用:

Map<CompanyNote>(t => t.Requires("type").HasValue("company"));
Map<OrderNote>(t => t.Requires("type").HasValue("order"));

type 的数据库类型为char(18)。 EF 生成 sql 好像它的nchar:

SELECT /* columns */
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = N'company'

N 是个问题,因为该表有数千行,它会阻止 SQL 使用索引。我需要查询才能这样看:

SELECT /* columns */
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'

这是我迄今为止尝试过的:

  • 添加Type 属性并将其映射为 Property(t =&gt; t.Type).IsFixedLength().HasMaxLength(18).IsUnicode(false);
  • 将列配置添加到继承映射中 Map&lt;CompanyNote&gt;(t =&gt; t.Requires("type").HasValue("company").IsFixedLength().HasMaxLength(18).IsUnicode(false));

两者都没有改变。不幸的是,我无法将数据库列类型更改为nchar

我如何告诉 Entity Framework 鉴别器列的类型是 char

更新:这是一个完整的示例

[TestFixture]
public class TphMappingFixture
{
    [Test]
    public void CompanyNotesQueryShouldNotHaveUnicodeDiscriminator()
    {
        string sql;
        using (TphTestContext context = new TphTestContext())
        {
            sql = context.CompanyNotes.ToString();
        }

        Console.WriteLine(sql);

      /* sql is:
        SELECT 
        '0X0X' AS [C1], 
        [Extent1].[id] AS [id], 
        [Extent1].[text] AS [text]
        FROM [dbo].[notes] AS [Extent1]
        WHERE [Extent1].[type] = N'company'
      */

        Assert.That(!sql.Contains("N'company'"));
    }
}

public abstract class TphTestNote
{
    public int Id { get; set; }
    public string Text { get; set; }
}

public class TphTestCompanyNote : TphTestNote
{
}

public class TphTestOrderNote : TphTestNote
{
}

public class TphTestNoteMap : EntityTypeConfiguration<TphTestNote>
{
    public TphTestNoteMap()
    {
        HasKey(t => t.Id);

        Property(t => t.Text)
            .HasMaxLength(254)
            .IsUnicode(false);

        ToTable("notes");

        Property(t => t.Id).HasColumnName("id");
        Property(t => t.Text).HasColumnName("text");

        Map<TphTestCompanyNote>(t => t.Requires("type").HasValue("company").IsUnicode(false));
        Map<TphTestOrderNote>(t => t.Requires("type").HasValue("order").IsUnicode(false));
    }
}

public class TphTestContext : DbContext
{
    static TphTestContext()
    {
        Database.SetInitializer<TphTestContext>(null);
    }

    public DbSet<TphTestCompanyNote> CompanyNotes { get; set; }
    public DbSet<TphTestOrderNote> OrderNotes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new TphTestNoteMap());
    }
}

【问题讨论】:

  • 我复制并粘贴了您的模型。我得到了完全相同的查询,但使用的是WHERE [Extent1].[type] = 'company'。你到底使用什么版本的EF?以及什么数据库和数据库版本?顺便说一句:如果您没有将 DB 初始化程序设置为 null,由于 EF 4.3(.1?) 中的错误,您会得到一个异常:stackoverflow.com/a/10020023/270591
  • 这很奇怪。我有 EF 4.3.1.0 和 SQL Server 2005。我的模型中没有上下文的连接字符串,而且它实际上从未命中数据库,所以我不确定它是否重要。
  • 如果您没有提供连接字符串(也没有上下文构造函数参数),EF 使用 System.Data.SqlClient 提供程序(称为“.NET Framework Data Provider for SQL Server”)并尝试连接到 @ 987654340@ 数据库实例。该提供程序适用于 SQL Server 2005 及更高版本,并且应该生成相同的 SQL(在我的理解中)。如果您使用了另一个提供程序,这将很重要(即使没有访问数据库),因为另一个提供程序可以生成其他 SQL。您使用的是 .NET 4.0 吗?还是 4.5?
  • .NET 4.0。我没有意识到它正在连接到我本地机器上的.\SQLEXPRESS(我通过停止服务并获得 ProviderIncompatibleException 来确认)。那个版本的 SQL Server 是 2008。
  • @Slauma,我不确定为什么使用相同的代码和相同版本的 EF 会看到不同的结果,但我发现了其他可行的方法。看我的回答。

标签: entity-framework-4 ef-code-first


【解决方案1】:

我仍然不确定为什么我看到的结果与@Slauma 不同,但我终于找到了适合我的东西。我在继承映射中明确将列类型设置为char

Map<TphTestCompanyNote>(t => t.Requires("type")
                              .HasValue("company")
                              .HasColumnType("char"));

Map<TphTestOrderNote>(t => t.Requires("type")
                            .HasValue("order")
                            .HasColumnType("char"));

以及生成的 SQL:

SELECT 
'0X0X' AS [C1], 
[Extent1].[id] AS [id], 
[Extent1].[text] AS [text]
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'

【讨论】:

  • 我也对此进行了测试,但是因为它对我的工作方式与您的原始代码相同,所以我认为这无关紧要并且没有任何区别。真的很奇怪,为什么这适用于您的而不是原始映射。我不知道可能是什么原因。
【解决方案2】:

我无法在 SQL 查询中重现 Unicode 字符串的使用。测试应用程序(带有 EF 4.3.1 的控制台应用程序):

using System;
using System.Data.Entity;
using System.Linq;

namespace EF43TPH
{
    public abstract class Note
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class CompanyNote : Note
    {
        public string ExtendedName { get; set; }
    }

    public class OrderNote : Note
    {
        public string AnotherExtendedName { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<Note> Notes { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<CompanyNote>()
                .Map<CompanyNote>(t => t.Requires("type").HasValue("company"));

            modelBuilder.Entity<OrderNote>()
                .Map<OrderNote>(t => t.Requires("type").HasValue("order"));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());

            using (var ctx = new MyContext())
            {
                try
                {
                    var query = ctx.Notes.OfType<CompanyNote>();
                    var queryString = query.ToString();
                }
                catch (Exception e)
                {
                    throw;
                }
            }
        }
    }
}

我在queryString得到的SQL查询是:

SELECT 
'0X0X' AS [C1], 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
[Extent1].[ExtendedName] AS [ExtendedName]
FROM [dbo].[Notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'

这个测试和你的代码有什么不同?

【讨论】:

  • 一个区别是我使用ctx.Set&lt;CompanyNote&gt;()而不是ctx.Set&lt;Note&gt;().OfType&lt;CompanyNote&gt;()进行查询。我将整理一个最小但完整的示例并更新我的问题。
  • @jrummell:如果我将 LINQ 查询更改为您的查询,我会得到相同的 SQL。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-08
  • 2023-04-06
  • 2014-04-20
  • 1970-01-01
相关资源
最近更新 更多