【问题标题】:mapping nhibernate parent/child relationship the 'other' way round以“其他”方式映射nhibernate父/子关系
【发布时间】:2012-02-03 22:13:39
【问题描述】:

使用 FluentNhibernate;

我正在尝试坚持一个看似简单的对象模型:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Config Config { get; set; }
}

public class Config
{
    public int ConfigId { get; set; }
    public int ProductId { get; set; }
    public string ConfigField1 { get; set; }
    public string ConfigField2 { get; set; }
}

数据库看起来像:(语法不正确)

CREATE TABLE [dbo].[Products](
[ProductId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL
)

CREATE TABLE [dbo].[Config](
[ConfigId] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NOT NULL,
[ConfigField1] [varchar](50) NULL,
[ConfigField2] [varchar](50) NULL
) ON [PRIMARY]

开箱即用的 fluent-nhibernate 将尝试将其映射为 Products 表上的外键,例如:

INSERT INTO Products (Name, Config_id) VALUES (?, ?);

我不希望它这样做,而是希望映射先插入 Products,然后再插入配置,并将 ProductId 插入到配置表中。

我已经尝试过覆盖和阅读链接,例如thisthis,但仍然无法让它做我想做的事。我正在使用现有数据和代码,因此我宁愿不更改数据库表定义或域对象。除了这个例子所描绘的内容之外,还有更多的事情发生,所以如果我们可以避免讨论领域模型设计,那就太好了。我有一个链接到这个项目的一个高峰here(假设数据库存在)

我目前的流利映射是:

public class ProductOverrides : IAutoMappingOverride<Product>
{
    public void Override(AutoMapping<Product> mapping)
    {
        mapping.Id(x => x.Id).Column("ProductId");            
        mapping.Table("Products");
    }
}

public class ConfigOverrides : IAutoMappingOverride<Config>
{
    public void Override(AutoMapping<Config> mapping)
    {
        mapping.Id(x => x.ConfigId);
    }
}

【问题讨论】:

  • 你试过了吗? brunoreis.com/tech/…
  • 你能解释一下这有什么帮助吗?这是一对一的关系,这不是我需要的,因为Config 有自己的主键ConfigId,但需要通过ProductId 链接回产品

标签: c# nhibernate fluent-nhibernate


【解决方案1】:

您试图通过将多方映射两次来将一对一关系映射为一对多。那是行不通的。 NHibernate 对一对一的定义很严格,要求双方有相同的主键,这样也行不通。

我有butted heads with this before,我发现最好的解决方法是将其建模为标准的多对多,但通过封装对它的访问仅允许集合中的一个项目。在您的情况下,我猜 Product 将是一侧,而 Config 是许多。

【讨论】:

  • 确认一下,这需要在Product 类中添加一个List&lt;Config&gt; Configs 属性吗?
  • 不,将集合(我建议设置映射而不是列表)添加为私有成员并使用访问策略对其进行映射。然后通过一个公共的 Config 属性控制集合,该属性只允许集合中的一个 Config。请参阅链接的问题。
  • 是的,首先它并不理想,因为我试图避免更改我的域对象只是为了取悦休眠。其次,我通过网络发送它,Set 我假设是一个我不能拥有的休眠类。
【解决方案2】:

我不确定 Config 是否在其他地方使用,但您可以忽略 ConfigId 作为其标识

public class Config
{
    public int Id { get; set; }
    public Product Product { get; set; }
    public string ConfigField1 { get; set; }
    public string ConfigField2 { get; set; }
}

public class ProductMap : ClassMap<Product>
{
    public class ProductMap()
    {
        HasOne(p => p.Config);
    }
}

public class ConfigMap : ClassMap<Config>
{
    public class ConfigMap()
    {
        Id(c => c.Id, "ProductId").GeneratedBy.Foreign("Product");

        References(c => c.Product, "ProductId");
        Map(c => ...);
    }
}

【讨论】:

  • 一如既往地感谢您的两个答案。这两种解决方案的问题是 Config 也被 another 类用作“组件”,它排除了使用 ProductId 作为键列(因为它没有在 Config 上定义 ConfigProduct 以外的类的属性。我认为最简单的方法是重新定义数据库以将 ConfigId 存储在 Product 表中
  • 当然,如果可能的话更改数据库是最简单的。但您也可以将另一个类上的 Config 映射为具有不同 joincolumn() 的组件
  • 那么你会怎么处理这条线:Id(c => c.Id, "ProductId").GeneratedBy.Foreign("Product");也就是说,考虑到Product Config 保存需要上述映射,其他类将如何将自己的 Id 添加到 Config 表中?
  • "by another class as a 'component'" --> 我的评论是针对您在我的其他答案中看到的组件映射。
  • 好的,明白了。我将使该方法与我的尖峰一起使用,并在完成时将其标记为已回答。 irl 我将只更新列,因为这对于 nhibernate 来说更容易;一般来说,nHibernate 是以“标准”方式执行此操作还是任意操作?
【解决方案3】:

另一个想法是作为组件加入和映射

public class ProductMap : ClassMap<Product>
{
    public class ProductMap()
    {
        Join("Config", join => 
        {
            join.KeyColumn("ProductId");
            join.Component(p => p.Config, c =>
            {
                c.Map(...);
            });
        }
    }
}

缺点是不能直接查询Config,必须通过Product查询

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 2017-08-29
    相关资源
    最近更新 更多