I am doing validation using DataAnnotation attributes on the Model classes, and the Model class is used for validation on both the Client and Server side of the application.
My problem is, I can’t figure out how to lazy load my Model’s properties without causing circular references
The libraries involved are:
- WCF Service Library
- Client-Side DataAccess Library
- Models Library
Because the Models library is used on both the Client and Server side for data validation, I cannot reference the DataAccess library from within the Models library. Therefore, how can I setup lazy-loading?
For example, I have a ConsumerModel which has a property of PhoneNumbers which should be lazy loaded. How can I load the PhoneNumberModels from within the ConsumerModel without referencing the Client-Side DAL?
Client-side DAL:
using MyModels;
public class ConsumerDataAccess
{
public ConsumerModel GetConsumerById(int id)
{
ConsumerDTO dto = WCFService.GetConsumer(id);
return new ConsumerModel(dto);
}
}
ConsumerModel:
public class ConsumerModel
{
public ObservableCollection<PhoneNumberModel> _phoneNumbers;
public ObservableCollection<PhoneNumberModel> PhoneNumbers
{
get
{
if (_phoneNumbers == null)
{
// Can't reference DataAccess Library since that would cause a Circular Reference
}
}
}
}
What are some alternative ways I could make this architecture work?
I would prefer to keep Validation with the Models, and to use the models from both the Client and Server side for validation. I would also prefer to keep using DataAnnotation for Validation.
EDIT
Here’s my final solution based on Lawrence Wenham’s answer if anyone is interested. I ended up using a delegate instead of an event.
DAL:
public class ConsumerDataAccess
{
public ConsumerModel GetConsumerById(int id)
{
ConsumerDTO dto = WCFService.GetConsumer(id);
ConsumerModel rtnValue = new ConsumerModel(dto);
ConsumerModel.LazyLoadData = LazyLoadConsumerData;
return rtnValue;
}
}
private object LazyLoadConsumerData(string key, object args)
{
switch (key)
{
case "Phones":
return PhoneDataAccess.GetByConsumerId((int)args);
default:
return null;
}
}
Model Library:
public class ConsumerModel
{
public delegate object LazyLoadDataDelegate(string id, object args);
public LazyLoadDataDelegate LazyLoadData { get; set; }
public ObservableCollection<PhoneNumberModel> _phoneNumbers;
public ObservableCollection<PhoneNumberModel> PhoneNumbers
{
get
{
if (_phoneNumbers == null && LazyLoadData != null)
{
_phoneNumbers = (ObservableCollection<PhoneNumberModel>)
LazyLoadData("Phones", ConsumerId);
}
return _phoneNumbers;
}
}
}
One way might be to raise an event in the
get {}of your Model classes properties, and then implement a lazy-loading manager on the client side that has a reference to your DAL. EG:Then in your Model classes:
The handler for the LazyLoadData event would have the job of fetching the data from the client side’s DAL, then storing it in the
.Dataproperty of LazyLoadEventArgs. EG: