0

This may seem like somewhat of a repeated question, however I feel like this is more of a specific scenario. I'm implementing DDD in a new Microservice and I'm using Dapper as an ORM. I have the following Domain object:

 internal Bundle(string warehouse, 
                    DateTime createdOn, 
                    int createdBy,
                    Company company,
                    BundleStatus status)
    {
        this.WarehouseID= warehouse;
        this.CreatedOn = createdOn;
        this.CreatedBy = createdBy;
        this.BundleStatus = status;
        this.Company = company;
        this.Packages= new HashSet<BundlePackages>();
    }

    private readonly HashSet<BundlePackages> packages;

    public string WarehouseID{ get; private set; }

    public int CreatedBy { get; private set; }
    
    public DateTime CreatedOn { get; private set; }

    public Company Company{ get; private set; }

    public BundleStatus Status { get; private set; }

    public IReadOnlyCollection<BundlePackage> Packages=> 
    shipments.ToList().AsReadOnly();

I'm querying the data in the following way:

  var sql = $@"SELECT * 
                FROM Bundle(except the Status, its going to be added later)

               SELECT ID, Name 
                FROM Packages";

        var dataResponse = await this.DbConnection.QueryMultipleAsync(sql);

        var agenda = dataResponse.Read<Bundle>().First();
        if(agenda != null)
        {
            var bundlePackages= bundle.GetType()
                .GetField("packages", BindingFlags.NonPublic | BindingFlags.Instance);

            bundlePackages.SetValue(bundle, dataResponse.Read<BundlePackages>());
        }

        return bundle;

Last but not least, since the Company is an EntityObject(private set for ID and CompanyName) and Dapper would not know how to map them, I'm using Dapper.FluentMapping:

        Map(bundle => bundle.Company.Id).ToColumn("CompanyID", caseSensitive: false);
        Map(bundle=> bundle.Company.Abbreviation).ToColumn("CompanyName", caseSensitive: false);

Now I have read just about every single article there is regarding Dapper mapping columns to private setters and everyone says that it "just works", as long as the column names match the property names. My column names match, however I get the following error:

A parameterless default constructor or one matching signature (System.Int32 ID, System.DateTime CreatedOn, System.Int32 CreatedBy, System.String DestinationWarehouseID, System.Int32 CompanyID, System.String CompanyName) is required for Models.Bundle materialization

1 Answers1

0

Your query SELECT * FROM Agendas needs to match the types/number of parameters in your constructor if you insist on keeping your properties with private setters. If you change them to public setters and add a default constructor it should work (if your property names match your query column names that is)

noontz
  • 1,782
  • 20
  • 29
  • I understood that much from the error, however the answers provided - [here](https://stackoverflow.com/questions/62437170/dapper-how-to-map-to-private-set-property-methods) and [here](https://stackoverflow.com/questions/12289168/will-dapper-not-work-with-members-that-have-custom-getters-setters) say something else. _Currently Dapper only maps data automatically to matching private primitive types, like string, int, etc, but not complex types._ – Svetlozar Stoykov Oct 02 '21 at 08:19