使用Fluent NHibernate

时间:2017-05-24 10:35:20

标签: c# sql-server nhibernate fluent-nhibernate

我有两个不同的类用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映射到File1File2? 我可以使用很多来定义用于关系的列吗? (Error方面。)

1 个答案:

答案 0 :(得分:2)

使用基类

对于这种情况,映射基类是一种常见的解决方案。这要求您的ID在File1File2之间是唯一的。 (File1中不存在File2中存在的复合ID,反之亦然。)为File1File2设置两个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媒体资源。

使用单独的外键

如果您不想引入基类,或者如果不能保证File1File2中文件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映射为File1File2,而不是将File1映射为实体。我不太了解Fluent,所以我只能用hbm语法来说明这一点。由你来找到适当的Fluent电话。

这要求您的ID在File2File1之间也是唯一的,否则错误可能会混杂在一起。 (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,您的组件必须实施GetHashCodeDescription覆盖,File1必须不可空。

使用collection of element

在这里,我不知道Fluent是否会处理这个问题。我也从未尝试过,而且文档非常简洁。无论如何,这是一个充满异国情调的映射,以尽可能避免。它需要一个额外的列来标识many-to-any是什么。 它允许您将错误的文件引用映射为单个对象属性,而不使用基类。它会支持File2Error具有共同ID。

备注:

如果将主键保留为实体而不是组件,则应在Equals类上添加主键。像序列id或其他任何技术。

最好避免使用"any"。否则将它们映射为composite ids并覆盖其组件和实体中的GetHashCodeError

您不需要在Error中映射外键ID,这对于文件实体的映射来说有点多余。您可以让Description类仅包含其public class Error { public FileBase File {get; set;} public string Description {get; set;} } 属性和文件实体属性。

因此,对于基类情况,它将是:

{{1}}