Reputation: 43097
I'm working with an existing database and using EF 4.3 Code First. I have an entity hierarchy that looks like this, where Note is the base class:
Note
- CompanyNote
- OrderNote
- etc
I'm using TPH with a discriminator column having the following mapping:
Map<CompanyNote>(t => t.Requires("type").HasValue("company"));
Map<OrderNote>(t => t.Requires("type").HasValue("order"));
The database type of type
is char(18)
. EF generates sql as if its nchar
:
SELECT /* columns */
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = N'company'
That N
is a problem because this table has many thousands of rows and it prevents SQL from using an index. I need to query to look this way:
SELECT /* columns */
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'
Here's what I've tried so far:
Type
property and mapping it with
Property(t => t.Type).IsFixedLength().HasMaxLength(18).IsUnicode(false);
Map<CompanyNote>(t => t.Requires("type").HasValue("company").IsFixedLength().HasMaxLength(18).IsUnicode(false));
Neither changes made a difference. Unfortunately, I can't change the database column type to nchar
.
How can I tell Entity Framework that the discriminator column is of type char
?
Update: Here's a complete example
[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());
}
}
Upvotes: 3
Views: 664
Reputation: 43097
I'm still not sure why I'm seeing different results than @Slauma, but I finally found something that works for me. I explicitly set the column type to char
in the inheritance mapping.
Map<TphTestCompanyNote>(t => t.Requires("type")
.HasValue("company")
.HasColumnType("char"));
Map<TphTestOrderNote>(t => t.Requires("type")
.HasValue("order")
.HasColumnType("char"));
And the resulting SQL:
SELECT
'0X0X' AS [C1],
[Extent1].[id] AS [id],
[Extent1].[text] AS [text]
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'
Upvotes: 3
Reputation: 177163
I can't reproduce the use of a Unicode string in the SQL query. Test application (Console app with 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;
}
}
}
}
}
The SQL query I get in queryString
is:
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'
What is different between this test and your code?
Upvotes: 1