2

I have the below domain model:

public class Company
{
    public int Id { get; private set; }
    public string Name { get; private set; } 
    public BlaBla BlaBla { get; private set; }
    ...
    ...

    public void ChangeName(string newName)
    {
        //business logic here

        Name = newName;
    }    
}

We have implemented the repository pattern using Entity Framework and it all works very well. For a very specific case (use a legacy database) we need to skip EF and use plain sql queries and do the mapping ourselves.

For the mapping the code (pseudo code) is as follows:

using connection
    using command
        company = new Company();
        while (reader.read())
            company.ChangeName(reader["company_name"]);
        end while
     end using
 end using

As you can see all the properties of Company are "private set" since we are practicing Domain Driven Design, so we can't write company.Id = reader["Id"] and we must use the domain methods to "populate" the properties of the Company object.

Is there an elegant way of doing this, like EF? How can I set the Id property without creating a method SetId(int id)?

Vagelis Ouranos
  • 482
  • 3
  • 14

2 Answers2

0

You can use PropertyInfo (Like the following):

foreach (PropertyInfo propInfo in theType.GetProperties())
{
    for (int i = 0; i < reader.FieldCount; i++)
    {
        if (reader.GetName(i).Trim().ToLower() == propInfo.Name.Trim().ToLower())
        {
            object asObj = reader.GetValue(i);
            if (asObj is System.DBNull) propInfo.SetValue(thisRow, null, null);
            else propInfo.SetValue(thisRow, reader.GetValue(i), null);
        }
    }
}

The type would be the typeof(YourType) that you want to map properties to.

Dave New
  • 38,496
  • 59
  • 215
  • 394
Mr. B
  • 2,845
  • 1
  • 21
  • 31
  • Since no one has posted another more complete answer i'll accept yours. I will try your solutions and tell you the results. – Vagelis Ouranos Dec 24 '14 at 08:42
  • Brute force your private members isn't DDD. – BAD_SEED Dec 24 '14 at 08:50
  • @marianoc84 Well as long as this is encapsulated in a factory used by the repository I do not see the issue. – plalx Dec 24 '14 at 14:17
  • @marianoc84 Isn't "Brute force your private memberes" kinda the way EF does the "mapping"? – Vagelis Ouranos Dec 24 '14 at 15:26
  • Also the data saved in the database are supposed to be correct. I just want to "fill" the domain model with these data. So it is supposed to be in a valid state. Creating a builder or a factory only for this work, it seems overkill to me. – Vagelis Ouranos Dec 24 '14 at 15:28
  • EF is an OR/M not a DDD tool. I know a lot of company (my company is in the list) where someone thinking to save time loves to manually alter database data (this action could broke some domain rules -unless you have a lot of db constraints-). The damage is done: you've (potentially) build an inconsistent object! In the end: you don't create builder/factory in this stage, you should already have one of this cause is the preffered way to build an object in DDD. – BAD_SEED Dec 25 '14 at 02:12
  • I agree, but the same applies for EF, doesn't it? If you mess with the db data, EF will load them even though there are broken domain rules. Also, from my research, builders/factories should be used when you need to create a complex object. When my object needs only one parameter to be created why not use the constructor? – Vagelis Ouranos Dec 26 '14 at 13:07
0

In DDD environment the creation isn't a task of constructor. Every constructor should be privated or protected to satisfy DDD. Sometimes, when EF (or other tools) is in the middle you have to provide a visible default constructor.

As said, construction isn't task for constructor but instead you can use factory, or even better a builder (latter gives you more elastic object creation). Than a more elegant solution could be:

Map SQL query output to a DTO.

public class CompanyDTO
{
    public int Id { get; set; }
    public string Name { get; set; } 
    public BlaBla BlaBla { get; set; }
    // no trace of business logic here
}

and in your retrieving logic, rather than build real Company object instead make the related DTO and use its members as builder's parameters:

//REPO PSEUDO CODE
using connection
    using command
        companyDTO = new CompanyDTO();
        while (reader.read())
            companyDTO.Name = reader["company_name"];
        end while
    end using
end using

// build your real `Company` object using as parameters the one 
// stored in the realted DTO.

company = CompanyBuilder.NewBuilder()
                        .WithCustomId(companyDTO.id)
                        .WithRegistryInfo(companyDTO.info1, companyDTO.info2, ....)
                        .WithOwnerInfo(companyDTO.owner1, ....)
                        .Build();

return company;

Based on your construction logic you can consider the possibility to get rid of DTO and call the build directly. I hope that I have correctly understood question.

BAD_SEED
  • 4,840
  • 11
  • 53
  • 110