我有一个讨厌的问题,我真的无法理解。
基本上我有一个定义如下的 DbContext
public interface ISettingsContext : IDisposable
{
IDbSet<Site> Sites { get; }
IDbSet<SettingGroup> Groups { get; }
IDbSet<SettingProperty> Properties { get; }
int SaveChanges();
}
public class SettingsContext : DbContext, ISettingsContext
{
public SettingsContext(string connectionStringName) : base(connectionStringName)
{
Sites = Set<Site>();
Groups = Set<SettingGroup>();
Properties = Set<SettingProperty>();
}
public SettingsContext() : this("DefaultTestConnectionString") { }
public IDbSet<Site> Sites { get; private set; }
public IDbSet<SettingGroup> Groups { get; private set; }
public IDbSet<SettingProperty> Properties { get; private set; }
#region Model Creation
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
MapSite(modelBuilder.Entity<Site>());
MapGroup(modelBuilder.Entity<SettingGroup>());
MapProperty(modelBuilder.Entity<SettingProperty>());
MapValue(modelBuilder.Entity<SiteSettingValue>());
MapXmlValue(modelBuilder.ComplexType<XmlValue>());
MapXmlType(modelBuilder.ComplexType<XmlTypeDescriptor>());
}
private void MapXmlType(ComplexTypeConfiguration<XmlTypeDescriptor> complexType)
{
complexType.Ignore(t => t.Type);
}
private void MapXmlValue(ComplexTypeConfiguration<XmlValue> complexType)
{
complexType.Ignore(t => t.Value);
}
private void MapValue(EntityTypeConfiguration<SiteSettingValue> entity)
{
entity.HasKey(k => new { k.PropertyId, k.SiteId }).ToTable("SiteValues", "settings");
entity.Property(k => k.PropertyId).HasColumnName("FKPropertyID");
entity.Property(k => k.SiteId).HasColumnName("FKSiteID");
entity.Property(k => k.Value.RawData).HasColumnName("Value").IsMaxLength();
entity.HasRequired(k => k.Site).WithMany(s => s.Settings).HasForeignKey(k => k.SiteId);
entity.HasRequired(k => k.Property).WithMany().HasForeignKey(k => k.PropertyId);
}
private void MapProperty(EntityTypeConfiguration<SettingProperty> entity)
{
entity.HasKey(k => k.Id).ToTable("Properties", "settings");
entity.Property(k => k.Id);
entity.Property(k => k.Name);
entity.Property(k => k.GroupId).HasColumnName("FKGroupID");
entity.Property(k => k.PropertyDescriptor.RawData).HasColumnName("TypeDescriptor").IsMaxLength();
entity.Property(k => k.DefaultValue.RawData).HasColumnName("DefaultValue").IsMaxLength();
entity.HasRequired(k => k.Group).WithMany(k => k.Properties).HasForeignKey(k => k.GroupId);
}
private void MapGroup(EntityTypeConfiguration<SettingGroup> entity)
{
entity.HasKey(k => k.Id).ToTable("Groups", "settings");
entity.Property(k => k.Id);
entity.Property(k => k.Name);
entity.HasMany(k => k.Properties).WithRequired(k => k.Group).HasForeignKey(k => k.GroupId);
}
private void MapSite(EntityTypeConfiguration<Site> entity)
{
entity.HasKey(k => k.Id).ToTable("Sites", "site");
entity.Property(k => k.Id);
entity.Property(k => k.Domain);
}
#endregion
}
由于我正在进行一些测试,我开始在这个上下文中工作,而不关心 IoC 和 DI,所以我直接针对具体类本身工作。
所以我写了这个查询:
public class SiteSettingsLoader : ILoader<SiteSettingsModel, int> {
...
var qSiteValues = from site in context.Sites
let settings = site.Settings
select new
{
SiteId = site.Id,
Settings = from value in settings
join property in context.Properties on value.PropertyId equals property.Id into props
from property in props
select new
{
PropertyId = property.Id,
Name = property.Name,
GroupId = property.GroupId,
Value = value.Value,
CanBeInherited = property.CanBeInherited
}
};
一切都很好。当我开始将上下文作为它实现的接口而不是它的真实类型传递时,问题就开始了。
using (ISettingsContext context = new SettingsContext())
using (SiteSettingsLoader loader = new SiteSettingsLoader(context))
{
SiteSettingsStore store = new SiteSettingsStore(loader);
dynamic settings = store.GetItem(1);
}
这是错误
无法创建“Settings.Entities.SettingProperty”类型的常量值。此上下文仅支持原始类型(“例如 Int32、String 和 Guid”)。
这怎么可能?微软是否在反射方面玩了一些肮脏的把戏?
编辑: XmlValue 和 XmlTypeDescriptor 都是以下接口的实现,我们使用它来自动将 XML 字段的内容读入适当的对象。
public interface IXmlProperty
{
string RawData { get; set; }
void Load(string xml);
XDocument ToXml();
}
基本上我们将字段的内容映射到 RawData 属性;在它的 setter 和 getter 中,我们解析/生成包含数据库 XML 的字符串。我知道这是一个丑陋的把戏,但它有效并完成了工作。