Rocky,
How hard would it be to allow the use of generics with the object factory. For instance, I am creating an object factory for each object now. But they are all doing the same thing. I can make an abstract base class for the factory with generics but I still have to create a factory for every object just so the BO has a concrete factory to use.
Does this make sense or am I just missing something somewhere?
Ryan
If there's no difference, why don't you just have one concrete factory?
To allow the use of generics would be hard, because I'd have to try to create the generic type, and if I couldn't find that type, I'd create a non-generic type. All that reflection is not cheap.
To require the use of generics would be easier, though still harder than the current scheme.
But I don't know that I need to do any of the above. You can do this if you'd like. Just create one concrete factory that is used by all objects. In your factory methods, you can do the same reflection I'd have to do to create a concrete instance of the generic type, and delegate the call to that instance.
I'm trying to keep ObjectFactory (as a concept) as simple as possible, because I don't yet know where Microsoft is going to go with ADO.NET Entity Framework. And my primary goal with ObjectFactory is to try and enable some cool scenarios around EF for future versions of EF (when it grows up).
So the more fancy/restrictive I make the implementation now, the more likely I am to introduce breaking changes when the future of EF becomes more clear.
As a result, I'm treating factories as "hands off" - allowing you nearly ultimate flexibility - including implementing your own models (like using generics) beneath the CSLA implementation.
Sorry to be so dumb, but reflection is not my strong suite by any means. So I am having trouble wrapping my head around how to implement one concrete factory for all objects because for instance in the Create method of the factory don't I have to create a new Project instance and return that? The part I am really having trouble with I guess is this. If I have one factory how does it know what type of object to create an instance of and return?
Thanks,
Ryan
To create an instance of your business object, you’d just
do this:
object newObject = Activator.CreateInstance(myType);
or
Dim newObject As Object = Activator.CreateInstance(myType)
You can get myType from the parameters passed to the factory method.
You really don’t need generics at all – they are just a convenience
in this case.
But if you really DO want generics, you’d use myType and reflection
to find and create an instance of your generic factory type. That is fancy
coding, and generics makes it quite a bit harder, but it can be done.
Rocky
Rocky,
Thanks for the help. I had managed to figure out what you posted and from what I can tell that would work great if you have a constructor with a parameter, especially if the parameter is an object. but what about this:
public
object Create()}
There is no parameters for the Create method, or is there a way to add them, when I tried to pass a Type in as a paramenter I get an exception "Ambigous match found". So I don't think I am doing something right.
That is a good point!!
I have to head to the airport, so I’ll be offline for a
few hours, but this you are right – this is a hole in the current design.
Rocky
From: rkelley
[mailto:cslanet@lhotka.net]
Sent: Monday, October 06, 2008 11:47 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: ObjectFactory Question
Rocky,
Thanks for the help. I had managed to figure out what you posted and from
what I can tell that would work great if you have a constructor with a
parameter, especially if the parameter is an object. but what about this:
public object Create()
{
var obj = new Project();
base.MarkNew(obj);
return obj;
}
There is no parameters for the Create method,
or is there a way to add them, when I tried to pass a Type in as a paramenter I
get an exception "Ambigous match found". So I don't think I am doing
something right.
nermin,
WOW! Thank you for posting that. I am still digesting most of it seems like you are/were tackling the same issues that I am tackling, Unit Testing, Mock Objects, etc..., hence the object factory.
Couple of questions for you though,
Are you using an IoC container to instantiate/inject your Business Objects? If so which one.
Are you using an ORM with your DTO objects? If so which ORM and are you injecting the "entity" object with the IoC container or just instantiating it directly from your BO. Reason I ask is I am using NHibernate and I have a Genereic IRepository that handles all of the db calls inside a Unit of Work. The reason the object factory is so appealing to me is because it brings greater seperation of concern and like you said that makes them very test friendly.
I had some guys tell me the other day that you should not use an IoC container to create instances of Business/Entity objects, so I was just curious if you were or not.
Unfortunately I got busy with few other tasks, as the deadline
for Csla.Net 3.6 approaches. The code was part of an example of custom
ObjectFactory and Factory Loader that I wanted to share with the community.
I do not have IoC plugged in yet. My plan was to use
StructureMap. It has been there for few years and I like its Fluent
syntax. The most popular IoC is most likely Windsor, by Castle Project,
and it is preferred one for NHibernate folks I believe. There is also MS
Unity, but it has been built by the same team that came up with
ObjectBuilder (too complex/hard to use, as well as poorly documented and
impossible to extend) so based on that experience most folks were hesitant to
adopt it. It is also new product on the market while StructureMap and
Windsor have been out there for few years.
As far as ORM, behind mine IRepository<T> is just a wrapper
class around Entity Frameworks DataContext. So EF does the table to DTO
mapping, and I use DTOs to populate Csla objects. The idea about generic
repository comes from MVC Store Front example, and they have essentially went
to NHibernate folks (Ayende) for an idea on implementation. I do think
that no matter if we use NHibernate or EF, pattern should be interchangable
Currently the Entity types are passed to the Generic Factory from
the ObjectFactoryAttribute – and the idea is to have the IoC container
pass them instead. However I do not have that implemented yet.
Take a look at the sample implementation:
public class SqlCustomerRepository : SqlRepositoryBase<Customers>
{
public override
IQueryable<Customers>
GetAll()
{
var customers = from
c in _db.Customers
orderby c.CompanyName
select c;
return customers;
}
}
And here is the SqlRepositoryBase:
public abstract
class SqlRepositoryBase<T>
: IRepository<T>
{
public NORTHWNDEntities
_db;
protected SqlRepositoryBase()
: this(new NORTHWNDEntities())
{
}
SqlRepositoryBase(NORTHWNDEntities db)
{
_db = db;
}
public abstract
IQueryable<T> GetAll();
}
Why does the Repository implement only GetAll(). As long
as you do not convert your IQueryable<T> to the list as ToList() the
actual Query expression is not evaluated run. That means that I can use
this IQueryable<T> result in my custom expressions in my BO to further
limit/filter results without any problem. (Take a look at the
CustomerList.FetchAll() for example).
That also means that I can add “Testable Filters” as
extension methods, like:
public void
FetchBy(IRepository<Orders> ordersRepository, CriteriaBase criteria)
{
var criteria1 = (CustomerFKCriteria)
criteria;
var orders =
from order in
ordersRepository.GetAll().WithCustomerID(criteria1.Id)
select order;
IsReadOnly = false;
foreach (var
order in orders)
Add(new OrderInfo(order));
IsReadOnly = true;
}
If you see the Linq expression inside OrderList.FetchBy(), you
will notice that I call ordersRepository.GetAll().WithCustomerID(criteria1.Id)
ordersRepository.GetAll() returns all records from
OrderList. The part of expression (and that is the “Fluent”
part) .WithCustomerID(int customerId) is just an extension method applied onto
the IQueryable<T> that returns another (filtered) IQueryable<T>.
That allows us to chain these expressions into a sentence, but also to test
them individually.
public static IQueryable<Orders>
WithCustomerID(this IQueryable<Orders> qry,
string customerID)
{
return from o in qry
where o.Customers.CustomerID == customerID
select o;
}
From: rkelley
[mailto:cslanet@lhotka.net]
Sent: Monday, October 06, 2008 1:40 PM
To: Nermin Dibek
Subject: Re: [CSLA .NET] RE: ObjectFactory Question
nermin,
WOW! Thank you for posting that. I am still digesting most of it seems like
you are/were tackling the same issues that I am tackling, Unit Testing, Mock
Objects, etc..., hence the object factory.
Couple of questions for you though,
Are you using an IoC container to instantiate/inject your Business Objects?
If so which one.
Are you using an ORM with your DTO objects? If so which ORM and are you
injecting the "entity" object with the IoC container or just
instantiating it directly from your BO. Reason I ask is I am using NHibernate
and I have a Genereic IRepository that handles all of the db calls inside a
Unit of Work. The reason the object factory is so appealing to me is because it
brings greater seperation of concern and like you said that makes them very
test friendly.
I had some guys tell me the other day that you should not use an IoC
container to create instances of objects, so I was just curious if you were or
not.
nermin,
Thanks for the additional insight, it has spawned a few more questions now.
As you know I am using NHibernate as the ORM, NHibernate populates the business object directly whereas what you are using uses a DTO object in between is that correct?
Would you mind showing us a sample of your DTO object and how that works in relation to the EF and the Csla object? Who populates the properites on the object? Is it automatic or do you have to populate each one individually?
I totally agree with you that the DAL should be interchangeable whether you are using NHibernate, EF, etc... this is what makes OO programming so awsome.
Based on the input you gave me yesterday I have almost got all of my 4 factories implemented and working. I am using structuremap to inject any dependencies they have on other services and I am also letting structuremap create the instances of the factory when it is needed.
One other question. How do you handle child updates from the parent object? A call to dataportal.updatechild does not seem to use the object factory to do the update. is this correct by design or should I be updating child object differently?
Ryan
Essentially I am using Entity Framework generated Entities as
DTOs. There is a problem with Entity Framework as it does not allow creation
of objects other than the ones that expose public constructors, and therefore
Csla.Net objects cannot be populated directly from EF. Rocky
might have mentioned earlier that EF team is working on building extensions
that would allow for Custom Factories to be registered with EF so that EF can
construct and map directly into different/complex BOs as CSLA. Rocky can
probably explain this problem a bit better, and actually he has built his
ObjactFactory concept as a placeholder for the EF custom factory concept.
Personally I prefer the simplest possible implementation, and if
the architecture does not require DTOs I would not use them, but for EF and
Linq to Sql we do not have choice yet
I will also let Rocky answer the child updates issue. That
– I believe is a missing piece, and I remember we discussed it couple of
weeks ago, but I guess have not gotten to completing yet.
As far as EF implementation – take a look at the
SqlOrdersRepository:
public class SqlOrdersRepository : SqlRepositoryBase<Orders>
{
public override
IQueryable<Orders>
GetAll()
{
var orders = from
o in _db.Orders
select o;
return orders;
}
}
The _db object is Entity Framework’s DataContext which
contains all of the Entities and their mapping to DB tables. Hence in
Linq above we are selecting everything from “Orders” entity, and
passing that as a query expression.
Then if you take a look at the OrderList.Fetch() CSLA BO:
public void
FetchBy(IRepository<Orders> ordersRepository, CriteriaBase criteria)
{
var criteria1 = (CustomerFKCriteria)
criteria;
var orders =
from order in
ordersRepository.GetAll().WithCustomerID(criteria1.Id)
select order;
IsReadOnly = false;
foreach (var
order in orders)
Add(new OrderInfo(order));
IsReadOnly = true;
}
In the Fetch() above you can see that we start with
ordersRepository.GetAll() Linq query, but then apply filter to it by chaining
in WithCustomerID(customerID). WithCustomerID(id) is an extenstion method
that allows me to apply filter – it accepts a Linq query from
orderRepository.GetAll() and applies the :
public static IQueryable<Orders>
WithCustomerID(this IQueryable<Orders> qry,
string customerID)
{
return from o in qry
where o.Customers.CustomerID == customerID
select o;
}
Actually I could have had the following in the Fetch() query,
without the need for an Extension method:
var orders =
from order in
ordersRepository.GetAll()
where order.Customers.CustomerID == criteria1.Id
select order;
The reason I have not taken the shorter rote is that with the
Extension method approach I can test independently OrderRepository.GetAll() and
the filter using my MockRepository
Then finally as you can see in Fetch I am using a List of
Customers entities, to populate the list of Csla Read Only objects –
OrderInfo. Each OrderInfo accepts a reference to the Order entity object
in its constructor and then we manually map the entity to the Csla BO –
not the best option, and more work than I want to, but I just could not try to
push for NHibernate also in this sample (Having, MVC, ExtJS, xUnit.net, and
StructureMap is enough of the unfamiliar tools for many Csla folks):
[Serializable]
public class OrderInfo : ReadOnlyBase<OrderInfo>
{
#region
Constructor
public OrderInfo(Orders
order)
{
LoadProperty<int>(OrderIdProperty,
order.OrderID);
LoadProperty<string>(OrderDateProperty,
order.OrderDate.HasValue ? order.OrderDate.Value.ToShortDateString():"");
LoadProperty<string>(ShipAddressProperty,
order.ShipAddress);
LoadProperty<string>(ShipCityProperty,
order.ShipCity);
LoadProperty<string>(ShipCountryProperty,
order.ShipCountry);
LoadProperty<string>(ShipNameProperty,
order.ShipName);
LoadProperty<string>(ShippedDateProperty,
order.ShippedDate.HasValue ? order.ShippedDate.Value.ToShortDateString():"");
LoadProperty<string>(ShipCompanyNameProperty,
order.ShipName);
LoadProperty<string>(ShipPostalCodeProperty,
order.ShipPostalCode);
}
From: rkelley
[mailto:cslanet@lhotka.net]
Sent: Tuesday, October 07, 2008 11:54 AM
To: Nermin Dibek
Subject: Re: [CSLA .NET] RE: RE: ObjectFactory Question
nermin,
Thanks for the additional insight, it has spawned a few more questions now.
As you know I am using NHibernate as the ORM, NHibernate populates the
business object directly whereas what you are using uses a DTO object in
between is that correct?
Would you mind showing us a sample of your DTO object and how that works in
relation to the EF and the Csla object? Who populates the properites on the
object? Is it automatic or do you have to populate each one individually?
I totally agree with you that the DAL should be interchangeable whether you
are using NHibernate, EF, etc... this is what makes OO programming so awsome.
Based on the input you gave me yesterday I have almost got all of my 4
factories implemented and working. I am using structuremap to inject any
dependencies they have on other services and I am also letting structuremap
create the instances of the factory when it is needed.
One other question. How do you handle child updates from the parent object?
A call to dataportal.updatechild does not seem to use the object factory to do
the update. is this correct by design or should I be updating child object
differently?
Ryan
Thanks for the information nermin. I really enjoy seeing how other minds think about similar problems. I am going to try and have a conversion of the ProjectTracker library done using Csla, Nhibernate, sturcturemap, and probably RhinoMocks (although from the test thread I may be able to satisfy the tests with structuremap) in the next day or two.
I would like to share the source so other people can look at it as reference or make critiques on it, you interested?
Actually let me share the problem I had with this. First
let me say that I prefer the IQueryable<T> as I believe that it allows me
to use Linq Expressions inside the BO. IQueryable<T> will work with
either Linq or EF. I also believe that Ayende has worked on Linq to
NHibernate, so that is why I was not concerned about that part.
As far as Mocks (actually Stubs) it is easy to SELECT from hard-coded
List<T> which will return IQueryable<T>.
The problem in this whole thing is not whether to use IEnumerable<DTO>
or IQueryable<DTO>, but rather that if you use LinqToSql object as DTO
that will not be re-usable as a EF Entity DTO. Those objects are similar but
actually different types. Therefore unless you define custom data objects
as DTOs there is no interoperability in this version of the pattern.
Being lazy myself I decided to limit my implementations to EF, and not worry
about interoperability until I have to.
BTW Rocky is the one that pointed to this problem in the
Repository pattern. I am curios to see whether you might have solution
for this also J
From: FrankM
[mailto:cslanet@lhotka.net]
Sent: Tuesday, October 07, 2008 2:05 PM
To: Nermin Dibek
Subject: Re: [CSLA .NET] RE: RE: RE: ObjectFactory Question
nermin, our IRopsitory returns IEnumerable<DTO>
instead of IQuerable<DTO> in your example. So BO does not care what kind
of dataaccess tech repository is using, either linq, EF, NH, and mock.
Ultimately I think you need to decide just how much flexibility you really need. Flexibility and decoupling are not free - in fact they are very expensive. So the business benefit to that flexibility had better be quite high to offset the cost.
When it comes to a DAL (ORM or not), there are levels at which flexibility may be desired:
Flexibility at each level becomes more expensive, in terms of dev cost/complexity and often performance. This is partially because each level as you go from 1 to 5 already exists to offer flexibility.
It is an old saying (joke) that the solution to any computer science problem is to add a layer of abstraction. And if you get so many layers of abstraction that things become complex, the answer is (yet again) to add another layer of abstraction.
Each layer already exists to provide abstraction over the lower layer(s). If you decide you want to be independent at level 5, then you are building a layer of abstraction over really big/complex layers of abstraction like EF or NHibernate. That's non-trivial and is not cheap. And I think you have to ask whether the benefit can offset that cost.
I'm not saying yea or nay, just saying that a responsible software architect/designer is always taking an objective look at the costs and benefits in an effort to come up with the best solution - which isn't always the ideal solution - just the best balance of cost/benefit.
But custom DTO is one more object I have to code for essentially
every Business entity. And that is the point that Rocky made lot clearer
than I was attempting to - every layer of abstraction costs in
development time and code size/complexity, as well as sometimes performance.
EF Entities are already generated from mapping, I did not have to code that, or
maintain that. Adding new set of object on top of those to achieve true
separation from DAL is a good thing, but at least for code that I work on –
EF works on several major DB vendors, and I get flexibility on DAL that way
while limiting myself to EF.
Unless flexibility is specified in requirements or is easy to accomplish
I tend to avoid adding extra. I think I mentioned it before, the only
reason for existence and passing these “DTO/Entities” in code I am
working on is the fact that EF still cannot map directly into CSLA BO Instance,
like rkelley is doing in his NHibernate implementation.
Just my 2c
From: FrankM
[mailto:cslanet@lhotka.net]
Sent: Tuesday, October 07, 2008 4:53 PM
To: Nermin Dibek
Subject: Re: [CSLA .NET] RE: RE: RE: RE: ObjectFactory Question
I see. I am using custom data objects as DTOs, so I don't
have this pain. And I can still use some basic linq query to those IEnumerable
objects. Maybe not all, but it's enough to our project.
Do you guys mind taking a look at this code and telling me if there is a better way to do this? I want my fetch method to take in criteriaBase because some object may have a SingleCriteria with a Guid others an int etc...
This is what I came up with, it works but I wonder if it could be better:
public override T Fetch(CriteriaBase criteria) { var obj = (T) Activator.CreateInstance(typeof (T), true); if (criteria.GetType().GetGenericTypeDefinition() == typeof (SingleCriteria<,>)) { Type[] genericArguments = criteria.GetType().GetGenericArguments(); Type originalType = genericArguments[1]; object criteriaValue = null; if(originalType.IsPrimitive) { if(originalType == typeof(int)) criteriaValue = ((SingleCriteria)criteria).Value; if (originalType == typeof(decimal)) criteriaValue = ((SingleCriteria) criteria).Value; if (originalType == typeof(float)) criteriaValue = ((SingleCriteria)criteria).Value; if (originalType == typeof(string)) criteriaValue = ((SingleCriteria)criteria).Value; if (originalType == typeof(object)) criteriaValue = ((SingleCriteria)criteria).Value; } else criteriaValue = ((SingleCriteria) criteria).Value; SingleCriteria newCriteria = new SingleCriteria(criteriaValue); using (UnitOfWork.Start(DatabaseKey)) { _repository.Load(obj,newCriteria.Value); } } MarkOld(obj); return obj; }
Alright guys, I have some code up you can look at / contribute to if you want. Some of the implementation may not be the best way or the most flexible so I am up for modifying it collectively if you are interested let me know:
Google Code Site:
The data portal creates exactly one instance of the factory loader object and then calls methods on that instance, potentially from different threads at the same time.
So any static or instance level fields in your factory loader must be used in a threadsafe manner, and if any objects are referenced by those fields, those objects must be threadsafe.
That is an awesome idea – and that is essentially what
this forum is about – us sharing ideas and code.
Could I suggest xUnit.net as a test framework. J
From: rkelley
[mailto:cslanet@lhotka.net]
Sent: Tuesday, October 07, 2008 1:54 PM
To: Nermin Dibek
Subject: Re: [CSLA .NET] RE: RE: RE: ObjectFactory Question
Thanks for the information nermin. I really enjoy seeing how other minds
think about similar problems. I am going to try and have a conversion of the
ProjectTracker library done using Csla, Nhibernate, sturcturemap, and probably
RhinoMocks (although from the test thread I may be able to satisfy the tests
with structuremap) in the next day or two.
I would like to share the source so other people can look at it as reference
or make critiques on it, you interested?
Regarding child objects:
The data portal operates now in one of two modes. Either a data
portal managed mode where the data portal manages your objects lifetimes, or a
factory mode where the data portal delegates all responsibility to your factory
object.
In the factory model all responsibility is delegated to
your factory objects. The data portal imposes as little restriction on the
factory objects as possible – thus providing as much flexibility as I can
manage. The trade-off is that the data portal does essentially nothing for you.
The ObjectFactory base class can be used to tap into some key behaviors that
are used by the data portal, so you can use them too, but otherwise what happens
in the factory is up to you.
There is no plan for a child factory concept. It is not clear to
me that I could create a factory model for child objects that would meet the
(unknown) requirements for some future version of EF, and NHibernate, and
your-custom-DAL.
In some theoretical future, where an ORM could directly create
and populate a CSLA object graph, there’d be no need for any child object
factory, because the ORM would do this. And that’s really the overarching
goal here – to allow/enable (and thus require) that the DAL (the object
factories) create and manipulate all the objects in the object graph.
Rocky
That is a good point – I didn’t think to mention the
fact that you can create your own factory loader and entirely change the way
the factory objects are created. for your scenario that may be the better
option.
Rocky
From: rkelley
[mailto:cslanet@lhotka.net]
Sent: Monday, October 06, 2008 1:39 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: ObjectFactory Question
nermin,
WOW! Thank you for posting that. I am still digesting most of it seems like
you are/were tackling the same issues that I am tackling, Unit Testing, Mock
Objects, etc..., hence the object factory.
Couple of questions for you though,
Are you using an IoC container to instantiate/inject your Business Objects?
If so which one.
Are you using an ORM with your DTO objects? If so which ORM and are you
injecting the "entity" object with the IoC container or just
instantiating it directly from your BO. Reason I ask is I am using NHibernate
and I have a Genereic IRepository that handles all of the db calls inside a
Unit of Work. The reason the object factory is so appealing to me is because it
brings greater seperation of concern and like you said that makes them very
test friendly.
I had some guys tell me the other day that you should not use an IoC
container to create instances of objects, so I was just curious if you were or
not.
Copyright (c) Marimer LLC