Search code examples
.net-corenhibernateasp.net-core-webapifluent-nhibernate-mapping

Insert nested object via JSON using web api with NHibernate


I'm writing an application that consist of a ReadAPI and a WriteAPI. The read API contains the domain classes, and uses EF CORE code first to generate the SQL DB, and to read from it.

The write API uses NHibernate to write to the database that is generated by EF Core. So far I have inserted 'simple' object via the write API, which has worked fine.

I'm encountering a problem now. I have a domain class, Driver, that has a nested object, Address, inside. At DB level a driver can have one address and an address can belong to multiple drivers. I'm trying to POST a JSON object, a driver object, via the write API. As to now, I've solved inserting the address by creating an address record in DB in advance, and giving the address ID in the JSON.

What I want to do now is giving the complete nested JSON object and have NHibernate generate the inserts for me. I have tried so many things but I feel like I am getting nowhere. Any advice would be much appreciated.

I'm using .Net Core with NHiberate 5.3.5, which has the mapping by code functionality already. If someone can solve it using Fluent NH instead, that is fine as well since I will convert it to NH 5.3.5 notation myself then.

My code:

Domain classes:

Driver:

namespace Models
{
    public class Chauffeur : IIdentifiable
    {
        public virtual long Id { get; set; }
        public virtual string Naam { get; set; }
        public virtual string Voornaam { get; set; }
        public virtual DateTime GeboorteDatum { get; set; }
        //todo validatie
        public virtual string RijksRegisterNummer { get; set; }
        public virtual RijbewijsTypes TypeRijbewijs { get; set; }
        public virtual bool Actief { get; set; }

        //rel adres
        public virtual long AdresId { get; set; }
        public virtual Adres Adres { get; set; }

        //rel tankkaart
        public virtual long TankkaartId { get; set; }
        public virtual Tankkaart Tankkaart { get; set; }

    }
}

Address:

namespace Models
{
    public class Adres : IIdentifiable
    {
        public virtual long Id { get; set; }
        public virtual string Straat { get; set; }
        public virtual int Nummer { get; set; }
        public virtual string Stad { get; set; }
        public virtual int Postcode { get; set; }
        public virtual ICollection<Chauffeur> Chauffeurs { get; set; }
    }
}

My DriverMap so far:

namespace WriteAPI
{
    public class ChauffeurMap : ClassMapping<Chauffeur>
    {
        public ChauffeurMap()
        {
            this.Table("Chauffeurs");

            this.Id(c => c.Id, c =>
            {
                c.Generator(Generators.Native);
                c.Type(NHibernateUtil.Int64);
                c.Column("Id");
                c.UnsavedValue(0);
            });
            
            this.Property(c => c.Naam);
            this.Property(c => c.Voornaam);
            this.Property(c => c.GeboorteDatum);
            this.Property(c => c.RijksRegisterNummer);
            this.Property(c => c.TypeRijbewijs);
            this.Property(c => c.Actief);

            this.Property(c => c.AdresId);

            this.Property(c => c.TankkaartId);
        }
    }
}

Using this mapping i could insert the nested object, by using an existing child address ID.

How I inserted this via a post:

{
                "Naam" : "Bart",
                "Voornaam" : "Jannsses",
                "AdresId" : 4,
                "GeboorteDatum" : "1979-04-25",
                "RijksRegisterNummer" : "999-888-7777",
                "TypeRijbewijs" : 1,
                "Actief" : true
}

How I would like to insert it in the future:

{
                "Naam" : "Bart",
                "Voornaam" : "Jannsses",
                "Adres" : {
                    "Straat": "Boomstraat", 
                    "Nummer": 1, 
                    "Stad": "Gent", 
                    "Postcode": 9000
                          },
                "GeboorteDatum" : "1979-04-25",
                "RijksRegisterNummer" : "999-888-7777",
                "TypeRijbewijs" : 1,
                "Actief" : true
}

Note that the ID of an address is auto generated at DB level.

Any help would be much appreciated.

Kind regards


Solution

  • You would need to add ManyToOne mapping in your ChauffeurMap class

     this.ManyToOne(x => x.Adres , m =>
            {
                m.Column("AdresId");
                // AdresId can be insert and update
                m.Update(true);
                m.Insert(true);
                m.Cascade(Cascade.None);
                m.Fetch(FetchKind.Join);
                m.NotFound(NotFoundMode.Exception);
                m.Lazy(LazyRelation.Proxy);
                m.ForeignKey("AdresId");
            });
    

    And you would also need additional mapping class for Adres as AdresMap. I hope you already have it. If not, please add it as below -

    public class AdresMap : ClassMapping<Adres> 
    {
        public AdresMap()
        {
        this.Table("Adres"); //Your table name
        this.Id(c => c.Id, c =>
            {
                c.Generator(Generators.Native);
                c.Type(NHibernateUtil.Int64);
                c.Column("Id");
                c.UnsavedValue(0);
            });
    
        Set(x => x.Chauffeurs, c =>
            {
                c.Key(k =>
                    {
                        k.Column("Id");
                        k.ForeignKey("AdresId");
                    });
                c.Inverse(true);
                c.Cascade(Cascade.None);
            },
            r => r.OneToMany(o => { }));
    
        this.Property(x => x.Straat );
        // ... other properties
       }
    }