In order to separate concerns, on my current project, I've decided to completely separate my DAL and BLL/Business objects in separate assemblies. I would like to keep my business objects as simple structures without any logic to keep things extremely simple. I would like if I could keep my Business Logic separate from my DAL also. So my application will tell my DAL to load my objects, my DAL will run off to the database and get the data, populate the object with the data and then pass it back to my BLL.
Question - how can I have my DAL in a separate assembly and push data into the read only fields?
Edit: I note that I can have a return type of ObjectBase but actually be returning an object or collection of objects that are derived form ObjectBase so to the outside world (outside my DAL) the properties would be read-only, but my derived types (only accessible inside my DAL) the properties are actually read/write.
You can set the read only property via a constructor.
This is a situation without a silver-bullet; the simplest options are limited or don't meet your requirements and the thorough solutions either begin to have smells or begin to veer away from simplicity.
Perhaps the simplest option is one that I haven't seen mentioned here: keeping the fields / properties private and passing them as out
/ ByRef
parameters to the DAL. While it wouldn't work for large numbers of fields it would be simple for a small number.
(I haven't tested it, but I think it's worth exploring).
public class MyObject()
{
private int _Id;
public int Id { get { return _Id; } } // Read-only
public string Name { get; set; }
// This method is essentially a more descriptive constructor, using the repository pattern for seperation of Domain and Persistance
public static MyObject GetObjectFromRepo(IRepository repo)
{
MyObject result = new MyObject();
return repo.BuildObject(result, out _Id);
}
}
public class MyRepo : IRepository
{
public MyObject BuildObject(MyObject objectShell, out int id)
{
string objectName;
int objectId;
// Retrieve the Name and Value properties
objectName = "Name from Database";
objectId = 42;
//
objectShell.Name = objectName;
Console.WriteLine(objectShell.Id); // <-- 0, as it hasn't been set yet
id = objectId; // Setting this out parameter indirectly updates the value in the resulting object
Console.WriteLine(objectShell.Id); // <-- Should now be 42
}
}
It's also worth noting that trying to keep your domain / business objects to the bare-minimum can involve more than you think. If you intend to databind to them then you'll need to implement IPropertyNotifyChanged, which prevents you from using automatically-implemented properties. You should be able to keep it fairly clean, but you will have to make some sacrifices for basic functionality.
This keeps your SoC model nicely, it doesn't add in too much complexity, it prevents writing to read-only fields and you could use a very similar model for serialization concerns. Your read-only fields can still be written to by your DAL, as could your serializer if used in a similar fashion - it means that conscious effort must be taken by a developer to write to a read-only field which prevents unintentional misuse.
Model Project
namespace Model
{
public class DataObject
{
public int id { get; protected set; }
public string name { get; set; }
}
}
Data Project
namespace Data
{
class DALDataObject : DataObject
{
public DALDataObject(int id, string name)
{
this.id = id;
this.name = name;
}
}
public class Connector
{
public static DataObject LoadDataObject(int objectId)
{
return new DALDataObject(objectId, string.Format("Dummy object {0}", objectId));
}
public static IEnumerable<DataObject> LoadDataObjects(int startRange, int endRange)
{
var list = new List<DataObject>();
for (var i = startRange; i < endRange; i++)
list.Add(new DALDataObject(i, string.Format("Dummy object {0}", i)));
return list;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With