Search code examples
c#n-tier-architecture

How to set primary key in decoupled datalayer


I'd like to decouple BL from DAL. Especially i want to have primary key protected (I don't want my business users to modify Item.Id).

In my DataLayer (let's imagine it is a simple sql table with autogenerated primary key) I try to insert item and update item.Id. Of course I can't because it is protected property.

Is there a way to do this without using a reflection? (I mean maybe my architecture is wrong...)

BusinessLayer:

public class Item
{
    public int Id { get; protected set; }

    public string Name { get; set; }
}

public interface IRepository<Item>
{
    void Insert(Item item);

    //and other CRUD operations
}

DataLayer (using EntityFramework with sqlserver):

public class EfRepository : IRepository<Item>
{
    EfContext ctx;     
    public void Insert(Item item)
    {      
        //EfContext uses its ItemEntity, so I have to map Item to EntityItem
        var mapped = AutoMapper.Map<Item, EntityItem>(item);
        ctx.Items.Add(mapped); 
        //after this operation EF will set primary key to mapped object
        //and now I need to set this to primary key to my business
        //domain object.
        item.Id = ?? // can't set protected property!!!
    }
}

Solution

  • To protect your logic against accidental modifications Id you can use "property injection pattern":

    public class Item
    {
        public Item() 
        { 
            _id = -1; 
        }
    
        public int Id 
        { 
            get 
            { 
                return _id; 
            }
    
            set
            {
                 if (_id != -1)
                 {
                     throw new OperationException("Item.Id has already been set");
                 }
    
                 _id = value;
            }
        }
    
        public string Name { get; set; }
    }