mapping nhibernate parent/child relationship the &

2019-02-27 14:55发布

问题:

using FluentNhibernate;

I am trying to persist a seemingly simple object model:

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; }
}

and the database looks like: (not syntactically correct)

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]

Out of the box fluent-nhibernate will try and map this as a foreign key on the Products table, eg:

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

I don't want it to do this, rather I was hoping the mapping would insert Products first then the config second with ProductId being inserted into the Config table.

I've pulled my hair out trying overrides and reading links such as this and this but still can't get it to do what I want. I am working with existing data and code so I would rather not change the database table definitions or the domain object. There is a bit more going on than what this example paints so if we could avoid discussions on domain model design that would be great. I have a link to a spike of this project here (assumes database exists)

my current fluent mappings are:

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);
    }
}

回答1:

You are trying to map a one-to-one relationship as a one-to-many by mapping what would be the many side twice. That won't work. NHibernate is strict in its definition of one-to-one and requires that both sides have the same primary key, so that won't work either.

I've butted heads with this before and the best workaround I found is to model it as a standard on-to-many but only allow one item in the collection by encapsulating access to the it. In your case I would guess that Product would be the one side and Config the many.



回答2:

I'm not sure if Config is used elsewhere but you could ignore ConfigId as its identity

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 => ...);
    }
}


回答3:

Another idea is to join and map as Component

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

Disadvantage is that you can not query Config directly, you have to query through Product