You can look at the CSLA .NET 3.5 ProjectTracker code - it uses an external DAL created using LINQ to SQL. The model itself doesn't allow for swapping out different DAL implementations, but it is a relatively small step to get there. I am hopeful that ADO.NET EF will allow a similar implementation where you don't need to worry about swapping out the DAL at the DataPortal_XYZ level, because EF will better encapsulate the solution - time will tell.
In terms of getting the business object's fields loaded with data, there are many options. ProjectTracker 3.5 uses a model not unlike previous versions, and quite similar to the DeepData example on my web site.
Or you can use partial classes (especially if you create separate projects for your client and server assemblies - using Visual Studio's linked file capability to share the actual core code files). Or you can use an inheritance model to do the same basic thing. Or you can use an interface-based model. Or you can use reflection. There are many options.
One thing I'm doing in my CSLA Light prototype is allowing the business object to specify that the data portal should call a "factory object" rather than creating/initializing the business object directly. You specify the factory object type, and you must implement a factory object for each root business type.
The model is required for CSLA Light, because you can't necessarily trust the Silverlight client (I don't think) and so there is a need for the business developer to get deeper into the middle of the data portal processing. Obviously this requires more coding, because the data portal is doing less work, but that's the tradeoff.
When doing this with the CSLA Light data portal you'll typically have your factory simply call the real business object's static factory methods:
[MobileFactory("MyDll.CustomerFactory,MyDll", "Create", "Load")]
public class Customer : BusinessBase<Customer>
{ ... }
public class CustomerFactory
{
public Customer Create()
{
// make sure Silverlight caller is allowed to do this
return Customer.NewCustomer();
}
public Customer Load(SingleCriteria<Customer, int> criteria)
{
// make sure Silverlight caller is allowed to do this
return Customer.GetCustomer(criteria.Value);
}
}
I might implement something similar for the .NET data portal too. It would require more work on the business developer's part though, because the .NET factory (unlike the Silverlight one) would have to do everything the data portal does today:
- Create an instance of the object (probably using Activator.CreateInstance())
- Trigger the data load or initialization or delete or update or insert
- Call MarkNew() or MarkOld() as appropriate
- Call the pre- and post- operation methods if you care (like the DataPortal_OnDataPortalComplete)
Luckily CSLA .NET 3.5 exposes the same helpers in Csla.Reflection that are used by the data portal itself (including all the cool dynamic method invocation and caching stuff), so you really can replicate what SimpleDataPortal does for you just the way it is done by CSLA - or you can invent your own scheme as long as the result is the same.
I'm not entirely sure I'll go down this road for .NET. For Silverlight it is very important. For .NET it mostly provides a very complicated alternative where people can really mess up the data portal if they do it wrong. On the upside though, it offers some pretty impressive flexibility in terms of invoking various advanced types of DAL.
It might help you, because your factory would be able to create an instance of a subclass of the real object - the subclass that implements the data access logic and loads the protected fields. That might look something like this:
[DataFactory("MyDataDll.CustomerFactory,MyDataDll", "Create", "Load")]
public class Customer : BusinessBase<Customer>
{ ... }
public class CustomerDal : Customer
{ ... }
public class CustomerFactory
{
public Customer Create()
{
var cust = new CustomerDal();
cust.LoadWithDefaults();
return cust;
}
public Customer Load(SingleCriteria<Customer, int> criteria)
{
var cust = new CustomerDal();
cust.LoadWithData(criteria.Value);
return cust;
}
}
Presumably LoadWithDefaults() and LoadWithData() would not only load the object's fields, but would call MarkNew() or MarkOld() as appropriate.
I don't know if this would cause issues with serialization - though I suspect it probably would. The serializers would serialize a type of CustomerDal and be unable to serialize it back into something called Customer on the caller - so now that I think about this, it really won't work unless CustomerDal implements ISerializable and in that implementation tells the serializer to deserialize into a different type (Customer in this case). That's pretty complex code to expect a business developer to write into every DAL class - so I'm liking this option less and less the more I think about it...
Rocky