1

我首先尝试使用代码进行一点 EF - 我无法弄清楚我哪里出了问题,这只是我自己的例子。我只是没有想法,想确定我哪里出错了......

首先是代表位置的简单 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 给我另一个错误....

啊!

最后,我想将 Location 抽象化,但这是否意味着我可以删除 hasvalue(“Location”)?

我想继续前进,但我很好奇我哪里做错了。谢谢!

4

2 回答 2

1

我认为你有点过于复杂了,这在 CF 周围很危险。
在代码优先的情况下,您必须坚持“经过试验和测试”的有效模式,否则混合事物和构造会让您很快陷入困境。

首先,为什么你需要映射并拥有 Loc_Type,我的意思是在类模型中?那是多余的,你真的会用你的“类”类型得到它,你的类类型是鉴别器,反之亦然。

这就是我认为的错误所说的,无论是提供还是“从映射中删除列”或其他东西。

因此,只需将其从 中删除,'Location'它就可以正常工作。此外,除非您想让您的 Db 有意义并被其他方使用等,否则您大部分时间实际上并不需要指定鉴别器,但这没关系。

如果你愿意,你可以把它抽象化,位置——这通常是做的,我认为你可以从映射中删除它,只有“真正实现的”类应该被映射,因为只有那些可以被“实例化”。

最后,由于各种原因,TPH 不是最“幸运”的解决方案,也是我认为最容易出错的解决方案,TPT、TPC 都工作得更加“流畅”。你不能让你的“子类”“属性不为空,等等等等。有关于那个的帖子。

希望这可以帮助。

编辑:如果您想控制“隐藏”鉴别器I think,您可以尝试手动调整该migration file列的具体值,设置它的大小等。如果这很重要(我猜代码首先应该在那里选择正确的值)。如果你不改变任何对事物如何运作的意义重大的改变,那么它应该运作。

于 2012-04-07T22:12:37.517 回答
1

问题是,当您使用列作为 TPH 映射的鉴别器时,您不能同时将该列映射到类中的属性。这是因为 EF 现在根据 .NET 类的类型控制该列的值。因此,您应该删除将 Loc_Type 属性映射到 Location 列的这一行:

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

如果您需要(或想要)为鉴别器列指定明确的列类型、大小等,那么您可以在 Map 调用中执行此操作。例如:

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

您不需要在表示位置类型的类中有任何属性。如果您确实想获得一个等效于 Loc_Type 的字符串值,那么您可以在 Location 中使用类似这样的内容:

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

然后在其他类中覆盖它。例如:

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

其余的代码看起来不错。

于 2012-04-07T23:20:59.817 回答