2012-04-07 2 views
1

Я сначала пытаюсь создать EF с кодом, и я не могу понять, где я ошибся, это просто пример моего собственного. Я просто из идей, и хотел бы пригвоздить меня, где я ошибаюсь ...TPH Simple Config/Discriminator issue

Сначала просто класс POCO, представляющий местоположение - местоположение может быть RadioStation или Merchant. Я еще не добавил дополнительные поля (которые появятся позже), так что прямо сейчас это просто TPH в простой конфигурации, как я могу это сделать.

namespace EFDataClasses.Entities 
{ 

    public class RadioStation : Location 
    { 
    public RadioStation() 
    { 
    } 

    } 

    public class Merchant : Location 
    { 
    public Merchant() 
    { 
    } 
    } 


    public class Location 
    { 
    public Location() 
    { 

    } 

public int Loc_ID { get; set; } 
public string Loc_Code { get; set; } 
public string Loc_Name { get; set; } 
public string Loc_Type {get;set;} 

} 
} 

то класс конфигурации:

namespace EFDataClasses.Mapping 
{ 


    public class LocationMap : EntityTypeConfiguration<Location> 
    { 
    public LocationMap() 
    { 
     // Primary Key 
     this.HasKey(t => t.Loc_ID); 

     // Properties 
     this.Property(t => t.Loc_ID) 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

     // Properties 
     this.Property(t => t.Loc_Code) 
      .IsRequired() 
      .HasMaxLength(50); 

     this.Property(t => t.Loc_Name) 
      .IsRequired() 
      .HasMaxLength(50); 


     this.Property(t => t.Loc_ID).HasColumnName("Loc_ID"); 
     this.Property(t => t.Loc_Code).HasColumnName("Loc_Code"); 
     this.Property(t => t.Loc_Name).HasColumnName("Loc_Name"); 

     //my discriminator property 
     this.Property(t => t.Loc_Type).HasColumnName("Loc_Type").HasColumnType("varchar").HasMaxLength(50).IsRequired(); 

     // Table & Column Mappings 
     this.Map(m => 
     { 
     m.ToTable("Location"); 
     m.Requires("Loc_Type").HasValue("Location"); 
     } 
     ) 
     .Map<RadioStation>(m => 
     { 
      m.ToTable("Location"); 
      m.Requires("Loc_Type").HasValue("RadioStation"); 
     } 
     ) 
     .Map<Merchant>(m => 
     { 
      m.ToTable("Location"); 
      m.Requires("Loc_Type").HasValue("Merchant"); 
     } 
     ) 
     ; 



    } 
    } 
} 

здесь контекст:

namespace EFDataClasses 
{ 
    public class MyContext : DbContext 
    { 
    static MyContext() 
    { 
     Database.SetInitializer<MyContext>(new DropCreateDatabaseAlways<MyContext>()); 
    } 

    public DbSet<EFDataClasses.Entities.Location> Locations {get; set;} 

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

и, наконец, класс программа, которая пытается добавить радиостанцию ​​..

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace EFConsole 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 

     var db = new EFDataClasses.MyContext(); 
     db.Locations.Add(new EFDataClasses.Entities.RadioStation() { Loc_Name = "Radio Station Name 1", Loc_Code = "RD1" }); 
     int chngs = db.SaveChanges(); 
     System.Diagnostics.Debugger.Break(); 

    } 
    } 
} 

Ошибка, по которой я получение - это ошибка проверки на Loc_Type, говорящая, что это обязательное поле. Мое впечатление здесь заключается в том, что EF заполнит это, когда я выберу соответствующий тип - и все мои чтения поддерживают это.

Если я добавить соответствующий тип расположения - EF дать мне другую ошибку ....

arggghhh!

В конце концов, я хотел бы сделать реферат местоположения, но означает ли это, что я могу отказаться от hasvalue («Location»)?

Я хотел бы переехать сюда, но мне любопытно, где я ошибся. благодаря!

ответ

0

Проблема заключается в том, что при использовании столбца в качестве дискриминатора для сопоставления TPH вы также не можете сопоставить этот столбец с свойством в своем классе. Это связано с тем, что EF теперь контролирует значение этого столбца на основе типа .NET-класса. Таким образом, вы должны удалить эту строку, которая делает отображение свойства Loc_Type в колонке Location:

// Remove this line: 
this.Property(t => t.Loc_Type).HasColumnName("Loc_Type").HasColumnType("varchar").HasMaxLength(50).IsRequired(); 

Если вам нужно (или хотят), чтобы явно указать тип столбца, размер и т.д. для столбца дискриминатора, то вы можете сделайте это в вызове карты. Например:

Map(m => 
{ 
    m.ToTable("Location"); 
    m.Requires("Loc_Type") 
     .HasValue("Location") 
     .HasColumnType("varchar") 
     .HasMaxLength(50) 
     .IsRequired(); 
} 

Вам не нужно иметь никаких свойств в классе, представляющем тип местоположения. Если вы хотите, чтобы получить строковое значение эквивалент Loc_Type, то вы можете использовать что-то вроде этого в Адрес:

public virtual string Loc_Type 
{ 
    get { return "Location"; } 
} 

Затем переопределить его в других классах. Например:

public override string Loc_Type 
{ 
    get { return "RadioStation"; } 
} 

Остальная часть кода выглядит хорошо.

+0

Я думаю, что вы на правильном пути здесь, но я смущен, почему я бы сказал EF, что файл сопоставления является значением для каждого подкласса, а затем также должен переопределить свойство Loc_Type? Я просто хочу контролировать имя и размер поля дискриминатора - используя конфигурацию по соглашению. – codeputer

+0

Вам не нужно переопределять свойство Loc_Type или даже иметь его вообще. Я просто показывал, что если вам нужна какая-то ценность для этого свойства. Если вы хотите настроить размер поля дискриминатора, вы делаете это в вызове Map. Я обновлю свой ответ, чтобы показать это. –

+0

Теперь я понимаю, что мое основное замешательство здесь было внесено полями FK и использование свободного API для отношений. В этом случае мы отображаем поля FK в классе, но для дискриминаторов мы этого не делаем. По этой причине я никогда не думал об исключении дискриминатора из класса. Мне кажется, что это несогласованность в дизайне API. Как вы думаете? – codeputer

1

Я думаю, что вы слишком много усложняете, и это опасно для CF.
С кодовым кодом вы должны придерживаться «проверенных и проверенных» шаблонов, которые работают, в противном случае смешивание вещей и конструкций вскоре вызовет у вас неприятности.

Во-первых, зачем вам нужно отображать и иметь Loc_Type вообще, я имею в виду модель класса? Это лишнее, вы получите это с помощью своего типа «class», тип вашего класса - дискриминатор и наоборот.

И вот что говорит об ошибке, я думаю, либо поставьте, либо «отбросьте столбец от отображения» или что-то еще.

Так что просто снимите это с 'Location', и он работает без проблем. Также вам не нужно указывать дискриминатор большую часть времени, если вы не хотите, чтобы ваш Db имел смысл и использовался другими сторонами и т. Д., Но это нормально.

Если вы хотите, вы можете сделать его абстрактным, местоположение - и это нормально сделано, и я думаю, что вы можете его отбросить, тогда из отображений должны быть отображены только «реальные реализованные» классы, поскольку только те могут быть «созданы».

И, наконец, TPH по разным причинам не самый «удачливый» вариант, и большинство ошибок, которые я думаю, TPT, TPC работают намного больше «жидкости». Вы не можете иметь свойства «дочерние классы» не равными нулю, и т. Д., Есть сообщения об этом.

надеюсь, что это поможет.

EDIT: если вы хотите контролировать «скрытый» дискриминатор I think, вы можете попробовать вручную отрегулировать migration file для этого столбца, в частности, установить его размер и т. Д. Если это важно (код сначала должен выбрать правильные значения я думаю). Если вы не измените ничего значительного в смысле того, как все должно работать.

+0

NSGaga - Я слышал, что вы говорите со стороны класса, но независимо от того, по соглашению и необходимости, код сначала добавит столбец с именем Discriminator. Я просто хочу контролировать имя и размер поля «Дискриминатор» в моем отображении поля. Если это поле можно сделать частным (может?), Еще лучше. Я бы хотел принять эту технологию, но сейчас я предпочитаю делать свой дизайн БД и в первую очередь придерживаться Table-per-Type! – codeputer

+0

вы могли бы управлять деталями, вручную настраивая файлы миграции, которые, я думаю, сделали бы трюк. «частный», не уверенный, что это сработает, если вы используете сопоставление, вы его сопоставляете, я думаю, вам нужно отпустить это. И @Arthur сказал то же самое, подтверждающее это, он парень из MS, работающий над этим материалом, поэтому он должен знать, что я предполагаю. – NSGaga

+0

Обратите внимание, что вы указываете таблицу за тип. Вы также можете сделать это с помощью EF Code First. Вы можете делать TPH, TPT или TPC (таблица для конкретного класса). Это отличная серия сообщений, описывающих варианты и способы их выполнения: http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code- first-ctp5-part-1-table-per-hierarchy-tph.aspx –