我有两个不同的类用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
}
一个有错误的类,包含每个类的描述。
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
?
我可以使用很多来定义用于关系的列吗? (Error
方面。)
答案 0 :(得分:2)
使用基类
对于这种情况,映射基类是一种常见的解决方案。这要求您的ID在File1
和File2
之间是唯一的。 (File1
中不存在File2
中存在的复合ID,反之亦然。)为File1
和File2
设置两个distintc表,而没有基础表类,你必须使用"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
课程映射到FileBase
媒体资源。
使用单独的外键
如果您不想引入基类,或者如果不能保证File1
和File2
中文件ID的唯一性,则必须将它们映射为两个单独的实体集合。 / p>
您的Error
课程类似于:
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;}
}
使用组件
您可以将Error
映射为File1
和File2
,而不是将File1
映射为实体。我不太了解Fluent,所以我只能用hbm语法来说明这一点。由你来找到适当的Fluent电话。
这要求您的ID在File2
和File1
之间也是唯一的,否则错误可能会混杂在一起。 (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>
中存在的复合ID,反之亦然。)
File2
同样适用于Error
。
Description
类不会保存文件ID属性,也不保存文件属性,只保留其Description
和其他属性(如果有)。
如果除了外键之外,您的Error类中只有Errors
,那么最好删除该类,只需将set
映射为list of components (字符串在您的情况)。
如果您想使用bag
而不是Equals
,您的组件必须实施GetHashCode
和Description
覆盖,File1
必须不可空。
在这里,我不知道Fluent是否会处理这个问题。我也从未尝试过,而且文档非常简洁。无论如何,这是一个充满异国情调的映射,以尽可能避免。它需要一个额外的列来标识many-to-any是什么。
它允许您将错误的文件引用映射为单个对象属性,而不使用基类。它会支持File2
和Error
具有共同ID。
备注:强>
如果将主键保留为实体而不是组件,则应在Equals
类上添加主键。像序列id或其他任何技术。
最好避免使用"any"。否则将它们映射为composite ids并覆盖其组件和实体中的GetHashCode
和Error
。
您不需要在Error
中映射外键ID,这对于文件实体的映射来说有点多余。您可以让Description
类仅包含其public class Error {
public FileBase File {get; set;}
public string Description {get; set;}
}
属性和文件实体属性。
因此,对于基类情况,它将是:
{{1}}