繁体   English   中英

流畅的NHibernate 3表关系,不包含主键和外键

[英]Fluent NHibernate 3 table relation without primary and foreign keys

背景资料

我有以下要与NHibernate映射的类:

public class Player
{
    public virtual int Id { get; set; }
    public virtual Type Type { get; set; }
    public virtual string ScreenName { get; set; }
    public virtual bool Unsubscribed { get; set; }
}

在数据库方面,我有以下表格:

-- New table
Player (
    int Id
    int TypeId (not null) -- foreign-key to Type table
    string ScreenName (not null) -- can be an EmailAddress, but not necessarily
)
Type (
    int Id
    string Name -- "Email", "Facebook", etc
)

播放器的屏幕名称可以是电子邮件地址(“ foo@bar.com”),Twitter屏幕名称(“ @FooBar”),Skype屏幕名称(“ foo.bar”)或类似的名称。 使用Fluent NHibernate映射Player的前三个属性非常容易:

public class PlayerMap : ClassMap<Player>
{
    public PlayerMap()
    {
        Id(x => x.Id);
        Map(x => x.ScreenName)
            .Not.Nullable();
        References(x => x.Type)
            .Column("TypeId")
    }
}

public class TypeMap : ClassMap<Type>
{
    public TypeMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
    }
}

但是Unsubscribed属性比较难,因为我必须从两个不能更改的旧表中获取该信息,并且必须以只读方式访问(不允许插入,更新或删除):

-- Legacy tables, can't change
EmailAddress (
    int Id
    string EmailAddress (not null) -- "foo@bar.com"
)
Unsubscribed (
    int Id
    int EmailAddressId (not null) -- foreign key to EmailAddress table
)

只能取消订阅电子邮件播放器,因此其他类型的播放器在EmailAddress或Unsubscribed表中都不会有一行。

这些是旧表的类:

public class EmailAddress
{
    public virtual int Id { get; set; }
    public virtual string Value { get; set; }
    public virtual IList<Unsubscription> Unsubscriptions{ get; set; }
}

public class Unsubscription
{
    public virtual int Id { get; set; }
    public virtual EmailAddress EmailAddress { get; set; }
}

这是他们的Fluent映射:

public class EmailAddressMap : ClassMap<EmailAddress>
{
    public EmailAddressMap()
    {
        ReadOnly();
        Id(x => x.Id);
        Map(x => x.Value)
            .Column("EmailAddress")
            .Not.Nullable();
        HasMany(x => x.Unsubscriptions)
            .KeyColumn("EmailAddressId");
    }
}

public class EmailOptOutMap : ClassMap<EmailOptOut>
{
    public EmailOptOutMap()
    {
        ReadOnly();
        Id(x => x.Id);
        References(x => x.EmailAddress)
            .Column("EmailAddressId");
    }
}

问题

我遇到的问题是尝试获取电子邮件播放器的未订阅信息。

我可以将Unsubscribed表与Player表相关联的唯一方法是通过中间的EmailAddress表,将EmailAddress.EmailAddress与Player.AddressIdentifier匹配,但是我很难弄清楚如何使用Fluent NHibernate做到这一点。

我已经查看了多个表的Join,但是我发现的所有示例仅处理2个表,而不是3个:

  1. 使用Fluent NHibernate加入表格
  2. 流利的Nhibernate左加入

一种可能的解决方案是对只读的Unsubscribed属性使用一个公式,以基于遗留表中存储的数据动态填充其值。 您可以按以下方式映射它:

Map(x => x.Unsubscribed).Formula("(CASE WHEN EXISTS (SELECT EA.Id FROM EmailAddress EA INNER JOIN Unsubscribed ON EA.Id = Unsubscribed.EmailAddressId WHERE EA.EmailAddress = ScreenName) THEN 1 ELSE 0 END)").ReadOnly();

当然,您可以通过为TypeId添加一个条件以过滤掉非电子邮件播放器来进一步改善选择查询。 另外,除非它在应用程序中的其他地方使用,否则您可以摆脱旧有的类和映射。

为了补充Denis的答案 ,我只想添加一些有关Hibernate文档中属性公式如何工作的文档

公式(可选):一个SQL表达式,用于定义计算属性的值。 计算属性没有自己的列映射。

强大的功能是派生属性。 根据定义,这些属性是只读的。 该属性值是在加载时计算的。 您将计算声明为SQL表达式。 然后,这将转换为加载实例的SQL查询中的SELECT子句子查询:

<property name="totalPrice" formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p WHERE li.productId = p.productId AND li.customerId = customerId AND li.orderNumber = orderNumber )"/>

您可以通过不声明特定列的别名来引用实体表。 在给定的示例中,这将是customerId。 如果不想使用该属性,也可以使用嵌套的映射元素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM