您想要一个具有Dictionary 属性的对象的原因是因为您想要快速查找:Give me the VmWord with the Localization with this Key。换句话说:给定一个键,您希望快速查找包含该键的 VnWordLocalization 对象。
在实体框架中,DbSet<...> 表示关系数据库中的表。关系型数据库不知道Dictionary这个概念。
幸运的是,数据库知道使用键进行快速查找的概念。通常这是主键,但您可以添加其他可以用作键的索引。
唉,你忘了告诉我们你想用哪个字符串来快速查找你的VmWordLocalizations。是En吗?或Pl?还是全新的钥匙?
如果它是一个全新的 Key,那么显然每个 VmWordLocalication 都有一个属性,我们将其命名为 Key,它与外键 VmWordId 组合是唯一的。如果是En 或Pl,则将其用作Key。
class VmWord
{
public int Id { get; set; }
// every VmWord has zero or more Localizations (one-to-many)
public virtual ICollection<VmWordLocalization> VmWordLocalizations { get; set; }
... // other properties
}
class VmWordLocalization
{
public int Id { get; set; }
// every VmWordLocalization belongs to exactly one VmWord using foreign key
public int VmWordId {get; set;}
public virtual VmWord VmWord {get; set;}
// every VmWordLocalization has a property Key, which is unique in combination
// with VmWordId
public string Key {get; set;}
}
注意:如果 Key 是整体唯一的,请考虑将其用作主 Key。
注意2:在实体框架中,非虚拟属性代表表中的列,表之间的关系由虚拟属性表示
注意 3:考虑坚持使用entity framework code-first conventions. 它消除了对属性或流畅 API 的需求。只有在有充分理由的情况下才偏离这些约定。必须输入更少的字符不是一个好理由。
如果Key 不能成为您的主键,您将不得不添加一个额外的快速查找:索引。这是在DbContext.OnModelCreating
protected overrid void OnModelCreating(...)
{
// Every VmWordLocalization has a property Key, which is unique per VmWordId
// create an index with (VmWordId, Key) as index key
var vmWordLocalizationEntity = modelBuilder.Entity<VmWordLocalization>();
// first index annotation: VmWordId:
vmWordLocalizationEntity.Property(entity => entity.VmWordId)
.IsRequired()
.HasColumnAnnotatin(IndexAnnotation.AnnotationName,
new IndexAnnotation(new IndexAttribute("index_VmWordId", 0)));
// 2nd index annotation: Key:
vmWordLocalizationEntity.Property(entity => entity.Key)
.IsRequired()
.HasColumnAnnotatin(IndexAnnotation.AnnotationName,
new IndexAnnotation(new IndexAttribute("index_Key", 1)));
}
标识符index_VmWord 和index_Key 可以是任何东西。它们只是命名索引列的标识符。
数字 0 和 1 给出了索引的排序顺序:首先是index_VmWordId,然后是index_Key。
现在,如果您有一个带有 Id == 10 的 VmWord,则可以添加带有 VmWordId == 10 和 Key == "Hello" 的 VmWordLocation。但是,如果您尝试使用这些值添加第二个VmWordLocation,您将得到一个异常,就像您将两个具有相同键的对象添加到字典中一样。
现在获取请求的VmWords 及其在字典中的本地化:
var vmWordsWithLocalizations = myDbContext.VmWords.Select(vmWord => new
{
// select only the properties you plan to use:
Id = vmWord.Id,
Name = vmWord.Name,
Localizations.VmWord.VmwordLocalizations
.Where(vmWordLocalization => ...) // only if you do't want all vmWordLocalizations
.ToDictionary(vmWordLocalization => vmWordLocalization.Key, // Dictionary Key
new // Dictionary value
{ // again: select only the properties you plan to use
Id = vmWordLocalization.Id,
En = vmWordLocalization.Em,
Pl = vmWordLocalization.Pl,
// no need: you know it equals vmWord.Id
// VmWordId = vmWordLocalization.VmWordId
}),
});
如果您必须经常这样做,请考虑创建一个扩展函数:
IEnumerable<VmWordWithDictionary> ToVmWordWithDictionary(this IQueryable<VmWord> vmWords)
{
return vmWords.Select(vmWord => new VmWordEx()
{
Id = vmWord.Id,
Name = vmWord.Name,
Localizations = vmWord.VmWordLocalizatons
.Where(vmWordLocalization => ...)
.ToDictionary(
vmWordLocalization => vmWordLocalization.Key // Key
vmWordLocalization => new VmWordLocalizationEx() // Value
{
Id = vmWordLocalization.Id,
En = vmWordLocalization.Em,
Pl = vmWordLocalization.Pl,
}),
});
注意:出于效率原因,我不想传输比需要更多的数据,所以我创建了两个额外的类,只包含我需要的数据。
注意:由于 Dictionary 的原因,返回值必须是 IEnumerable。在此之后您不能再执行 IQueryable LINQ 语句了