使用 Fluent NHibernate 将一个实体的关系映射到另外两个实体
Mapping a relationship from an entity to two other entities with Fluent NHibernate
我有两个不同的class映射到 Fluent NHibernate
public class File1Map: ClassMap<File1> {
CompositeId()
.KeyProperty(x => x.IdFile)
.KeyProperty(x => x.IdRow);
HasMany(x => x.Errors).AsBag().KeyColumns.Add("IdFile", "IdRow");
}
public class File2Map: ClassMap<File2> {
CompositeId()
.KeyProperty(x => x.IdFile)
.KeyProperty(x => x.IdRow);
HasMany(x => x.Errors).AsBag().KeyColumns.Add("IdFile", "IdRow");
}
public class File1 {
public int IdFile {get; set;}
public int IdRow {get; set;}
public List<Error> Errors {get; set;}
// ...other properties different from File2
}
public class File2 {
public int IdFile {get; set;}
public int IdRow {get; set;}
public List<Error> Errors {get; set;}
// ...other properties different from File1
}
还有一个有错误的 class,包含每个 class 的描述。
public class ErrorMap: ClassMap<Error> {
Map(p => p.IdFile);
Map(p => p.IdRow);
Map(p => p.Description);
}
public class Error {
public int IdFile {get; set;}
public int IdRow {get; set;}
public string Description {get; set;}
}
如何将 Error
映射到 File1
和 File2
?
我可以使用 has many 来定义要用于关系的列吗? (Error
边。)
使用基数class
对于这种情况,映射一个基数 class 是通常的解决方案。这要求您的 ID 在 File1
和 File2
中是唯一的。 (在 File2
中无法找到 File1
中存在的复合 ID,反之亦然。)对于 File1
和 File2
有两个不同的 table 而没有table 为基础 class,你必须使用 "table per concrete class strategy".
public class FileBaseMap: ClassMap<FileBase> {
CompositeId()
.KeyProperty(x => x.IdFile)
.KeyProperty(x => x.IdRow);
HasMany(x => x.Errors).AsBag().KeyColumns.Add("IdFile", "IdRow");
// One table per concrete class.
UseUnionSubclassForInheritanceMapping();
}
public class File1Map: SubclassMap<File1> {
// Other properties mapping
}
public class File2Map: SubclassMap<File2> {
// Other properties mapping
}
public abstract class FileBase {
public int IdFile {get; set;}
public int IdRow {get; set;}
public List<Error> Errors {get; set;}
}
public class File1 : FileBase {
// ...other properties different from File2
}
public class File2 : FileBase {
// ...other properties different from File1
}
然后您可以将 Error
class 映射到 FileBase
属性。
使用单独的外键
如果您不想引入基数 class,或者如果您不能保证文件 ID 在 File1
和 File2
之间的唯一性,则必须将它们映射为两个单独的实体集合。
您的 Error
class 看起来像:
public class Error {
public int? IdFile1 {get; set;}
public int? IdRow1 {get; set;}
public int? IdFile2 {get; set;}
public int? IdRow2 {get; set;}
public string Description {get; set;}
public File1 File1 {get; set;}
public File2 File2 {get; set;}
}
使用组件
您可以将其映射为 File1
和 File2
中的 list of components ,而不是将 Error
映射为实体。我对 Fluent 了解不多,所以我只能用 hbm 语法来说明这一点。由您找到合适的 Fluent 调用。
这要求您的 ID 在 File1
和 File2
中也是唯一的,否则可能会出现错误。 (File1
中不存在的组合 id 应该在 File2
中找到,反之亦然。)
<class name="File1">
<!-- id and other properties here -->
<bag name="Errors" table="Error">
<key>
<column name="IdFile" />
<column name="IdRow" />
</key>
<composite-element class="Error">
<property name="Description" />
</composite-element>
</bag>
</class>
File2
也是如此。
Error
class 不会保存文件 ID 属性或文件 属性,但只会保存其 Description
和其他属性(如果有的话)。
如果除外键外,您的错误 class 中只有 Description
,您可能最好删除 class 并将 Errors
映射为a collection of element(你的字符串)。
如果您想使用 set
而不是 bag
,您的组件将必须实现 Equals
和 GetHashCode
覆盖,以及 Description
必须不可为空。
这里又一次,我不知道 Fluent 是否处理了这个问题。我也从未尝试过,而且文档非常简洁。无论如何,这是一个要尽可能避免的异国情调的映射。它需要一个额外的列来识别什么是 "any"。
它允许您将错误的文件引用映射为单个对象 属性,而没有基 class。它将支持 File1
和 File2
具有共同的 ID。
备注:
如果您将 Error
class 作为一个实体而不是一个组件来保存,您应该添加一个主键。技术性的,例如序列 ID 或其他。
最好避免在其组件和实体中使用 composite ids. Otherwise map them as composite identifier 并覆盖 Equals
和 GetHashCode
。
不需要映射Error
中的外键id,这对于文件实体的映射有点多余。您可以让 Error
class 仅包含其 Description
属性 和文件实体 属性.
所以对于基本 class 情况,它将是:
public class Error {
public FileBase File {get; set;}
public string Description {get; set;}
}
我有两个不同的class映射到 Fluent NHibernate
public class File1Map: ClassMap<File1> {
CompositeId()
.KeyProperty(x => x.IdFile)
.KeyProperty(x => x.IdRow);
HasMany(x => x.Errors).AsBag().KeyColumns.Add("IdFile", "IdRow");
}
public class File2Map: ClassMap<File2> {
CompositeId()
.KeyProperty(x => x.IdFile)
.KeyProperty(x => x.IdRow);
HasMany(x => x.Errors).AsBag().KeyColumns.Add("IdFile", "IdRow");
}
public class File1 {
public int IdFile {get; set;}
public int IdRow {get; set;}
public List<Error> Errors {get; set;}
// ...other properties different from File2
}
public class File2 {
public int IdFile {get; set;}
public int IdRow {get; set;}
public List<Error> Errors {get; set;}
// ...other properties different from File1
}
还有一个有错误的 class,包含每个 class 的描述。
public class ErrorMap: ClassMap<Error> {
Map(p => p.IdFile);
Map(p => p.IdRow);
Map(p => p.Description);
}
public class Error {
public int IdFile {get; set;}
public int IdRow {get; set;}
public string Description {get; set;}
}
如何将 Error
映射到 File1
和 File2
?
我可以使用 has many 来定义要用于关系的列吗? (Error
边。)
使用基数class
对于这种情况,映射一个基数 class 是通常的解决方案。这要求您的 ID 在 File1
和 File2
中是唯一的。 (在 File2
中无法找到 File1
中存在的复合 ID,反之亦然。)对于 File1
和 File2
有两个不同的 table 而没有table 为基础 class,你必须使用 "table per concrete class strategy".
public class FileBaseMap: ClassMap<FileBase> {
CompositeId()
.KeyProperty(x => x.IdFile)
.KeyProperty(x => x.IdRow);
HasMany(x => x.Errors).AsBag().KeyColumns.Add("IdFile", "IdRow");
// One table per concrete class.
UseUnionSubclassForInheritanceMapping();
}
public class File1Map: SubclassMap<File1> {
// Other properties mapping
}
public class File2Map: SubclassMap<File2> {
// Other properties mapping
}
public abstract class FileBase {
public int IdFile {get; set;}
public int IdRow {get; set;}
public List<Error> Errors {get; set;}
}
public class File1 : FileBase {
// ...other properties different from File2
}
public class File2 : FileBase {
// ...other properties different from File1
}
然后您可以将 Error
class 映射到 FileBase
属性。
使用单独的外键
如果您不想引入基数 class,或者如果您不能保证文件 ID 在 File1
和 File2
之间的唯一性,则必须将它们映射为两个单独的实体集合。
您的 Error
class 看起来像:
public class Error {
public int? IdFile1 {get; set;}
public int? IdRow1 {get; set;}
public int? IdFile2 {get; set;}
public int? IdRow2 {get; set;}
public string Description {get; set;}
public File1 File1 {get; set;}
public File2 File2 {get; set;}
}
使用组件
您可以将其映射为 File1
和 File2
中的 list of components ,而不是将 Error
映射为实体。我对 Fluent 了解不多,所以我只能用 hbm 语法来说明这一点。由您找到合适的 Fluent 调用。
这要求您的 ID 在 File1
和 File2
中也是唯一的,否则可能会出现错误。 (File1
中不存在的组合 id 应该在 File2
中找到,反之亦然。)
<class name="File1">
<!-- id and other properties here -->
<bag name="Errors" table="Error">
<key>
<column name="IdFile" />
<column name="IdRow" />
</key>
<composite-element class="Error">
<property name="Description" />
</composite-element>
</bag>
</class>
File2
也是如此。
Error
class 不会保存文件 ID 属性或文件 属性,但只会保存其 Description
和其他属性(如果有的话)。
如果除外键外,您的错误 class 中只有 Description
,您可能最好删除 class 并将 Errors
映射为a collection of element(你的字符串)。
如果您想使用 set
而不是 bag
,您的组件将必须实现 Equals
和 GetHashCode
覆盖,以及 Description
必须不可为空。
这里又一次,我不知道 Fluent 是否处理了这个问题。我也从未尝试过,而且文档非常简洁。无论如何,这是一个要尽可能避免的异国情调的映射。它需要一个额外的列来识别什么是 "any"。
它允许您将错误的文件引用映射为单个对象 属性,而没有基 class。它将支持 File1
和 File2
具有共同的 ID。
备注:
如果您将 Error
class 作为一个实体而不是一个组件来保存,您应该添加一个主键。技术性的,例如序列 ID 或其他。
最好避免在其组件和实体中使用 composite ids. Otherwise map them as composite identifier 并覆盖 Equals
和 GetHashCode
。
不需要映射Error
中的外键id,这对于文件实体的映射有点多余。您可以让 Error
class 仅包含其 Description
属性 和文件实体 属性.
所以对于基本 class 情况,它将是:
public class Error {
public FileBase File {get; set;}
public string Description {get; set;}
}