我正在尝试使用代码的EF - 我无法弄清楚我的错误在哪里就是我自己的例子。我只是出于想法,并想确定我出错的地方......
首先是表示位置的简单POCO类 - 位置可以是RadioStation,也可以是商家。我没有添加其他字段(稍后会出现),所以现在它只是一个简单的配置中的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(“位置”)?
我想继续前进,但我很好奇我做错了什么。谢谢!
答案 0 :(得分:1)
我认为你的事情过于复杂,这对CF来说很危险 使用代码优先,您必须坚持使用“经过试验和测试”的模式,否则混合内容和结构会很快让您陷入困境。
首先,为什么你需要映射并拥有Loc_Type,我的意思是在类模型中?这是多余的,你真的会用你的'类'类型得到它,你的类类型是鉴别器,反之亦然。
这就是我认为错误的说法,无论是提供还是“从列中删除列”等等。
所以只需从'Location'
中删除它,它就可以解决问题。你也不需要在大多数时候指定鉴别器,除非你想让你的Db有意义并且被其他方面使用等等。
如果你想要你可以使它抽象,位置 - 这通常已经完成,我认为你可以从映射中删除它,只有'真正实现'的类应该映射为只有那些可以'实例化'。
最后,TPH出于各种原因而不是最“幸运”的解决方案,而且我认为最容易出错,TPT,TPC都更加“流畅”。你不能让你的'子类''属性为非null等等。有帖子就可以了。
希望这会有所帮助。
编辑:如果你想控制'隐藏'鉴别器I think
,你可以尝试专门手动调整该列的migration file
,设置它的大小等。如果这很重要(代码首先应该在那里选择正确的值我猜)。如果你没有改变任何重要的东西,那么事情应该如何发挥作用。
答案 1 :(得分:1)
问题在于,当您使用列作为TPH映射的鉴别器时,您也无法将该列映射到类中的属性。这是因为EF现在根据.NET类的类型控制该列的值。因此,您应该删除执行Loc_Type属性映射到Location列的这一行:
// Remove this line:
this.Property(t => t.Loc_Type).HasColumnName("Loc_Type").HasColumnType("varchar").HasMaxLength(50).IsRequired();
如果您需要(或想要)为discriminator列指定显式列类型,大小等,那么您可以在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"; }
}
其余的代码看起来很好。