我有以下数据结构:
+---------+
|Resume |
+---------+
|Id (PK) |
|IsActive |
|... |
|.. |
|. |
+---------+
+--------------------+
|Resume_Translation |
+--------------------+
|ResumeId (PK, FK) |
|Language (PK) |
|Title |
|Description |
|... |
|.. |
|. |
+--------------------+
所以我可以拥有两个连接表的数据:
+----------------------------------------------------------+
|Id | IsActive | ResumeId | Language | Title | Description |
+----------------------------------------------------------+
|1 | true | 1 | 'fr' | 'One' | 'One desc' |
|1 | true | 1 | 'pl' | 'Raz' | 'Raz Opis' |
|2 | true | 2 | 'fr' | 'B' | 'bla bla' |
|3 | true | 3 | 'fr' | 'C' | 'C bla bla' |
+----------------------------------------------------------+
从我的域名来看,我只关心Resume
实体。我不希望Resume
实体的集合为Resume_Translations
,因为我只有一个Resume
实体具有当前翻译。
public class Resume
{
public virtual int Id{ get; protected internal set; }
public virtual string Language { get; protected internal set; }
public virtual string Title { get; protected internal set; }
public virtual string Description { get; protected internal set; }
public virtual bool IsActive { get; protected internal set; }
}
我目前与Fluent NHibernate的映射如下:
public class ResumeMap : ClassMap<Resume>
{
public ResumeMap()
{
Table("Resume");
Id(x => x.Id);
Map(x => x.IsActive);
// other properties
Join("Resume_Translation", m =>
{
m.Fetch.Join();
m.Map(x => x.Language).Length(5);
m.Map(x => x.Title).Length(100);
m.Map(x => x.Description).Length(200);
});
}
}
我可以从存储库中获得我想要的东西,而不仅仅是传递WHERE谓词的简历和我想要的语言。
但是我在插入和更新值方面遇到了一些问题。
我的问题是:如何定义NHibernate仅在Resume_Translation表中插入新记录而不是更新当前实体的记录的映射?
所以我想要实现的是,如果我在数据库中有以下记录:
|2 | true | 2 | 'fr' | 'B' | 'bla bla' |
加入对于表之间的一对一关系很有用,所以如果我把它放到我的实体中并且我改变了语言和翻译,那么nhibernate正在执行更新,我可以理解它。如果我尝试通过不同的语言和翻译添加具有相同Id的新实体,则nhibernate会产生一个错误,即密钥已经存在并且我也理解它。
所以,当然,我走的是错误的道路,但如果有人能够指出我如何能够实现我想要的映射的正确解决方案,我将非常感激。
另一个问题是,您如何从业务角度处理实体及其翻译?
先谢谢你的帮助。
托马斯
答案 0 :(得分:2)
似乎与我有一对多的关系。我个人会在简历对象中收集 ResumeTranslation 对象。然后,我会将其作为标准对象进行映射。
然后,您可以将另一个属性 ActiveResumeTranslation 添加到代表您current translation
的简历实体。
答案 1 :(得分:2)
使用字典作为密钥使用字典怎么样?
public class ResumeTranslation
{
public virtual string Title { get; protected internal set; }
public virtual string Description { get; protected internal set; }
}
public class Resume
{
public virtual int Id{ get; protected internal set; }
// language is the key to the translation
// you may even want to hide the dictionary from the public interface of
// this class and only provide access to a "current" language.
public virtual IDictionary<string, ResumeTranslation> Translations { get; private set; }
public virtual bool IsActive { get; protected internal set; }
}
并相应地将其映射为具有复合元素的map
(对不起,我没有流利使用,所以不要问我它会是什么样子)。它与您的数据库模型完全匹配。
答案 2 :(得分:2)
Stefan走在正确的轨道上。我已经调整了他的建议,使其具有双向关联,这将使更新变得更容易。这种方法的一个缺点是,您需要在插入时手动分配ResumeTranslation实例的Resume属性,以便NHibernate将Resume表键正确分配给ResumeTranslation行。因此,考虑到您正在映射的关联,这就是它在Fluent NH中的外观:
public class ResumeTranslation
{
public virtual string Title { get; protected internal set; }
public virtual string Description { get; protected internal set; }
//Needed for bi-directional association:
public virtual Resume Resume { get; set; }
}
public class ResumeTranslationMap : ClassMap<ResumeTranslation>
{
public ResumeTranslationMap()
{
Table("ResumeTranslation");
CompositeId()
.KeyReference(kp => kp.Resume, "ResumeId")
.KeyProperty(kp => kp.Language, "Language");
Map(x => x.Title);
Map(x => x.Description);
}
}
public class ResumeMap : ClassMap<Resume>
{
public ResumeMap()
{
Table("Resume");
Id(x => x.Id);
Map(x => x.IsActive);
// other properties
HasMany(c => c.Translations)
.Inverse()
.KeyColumn("id") //May not be required but here for reference
.Cascade.All();
}
}