ObjectFactory Question

ObjectFactory Question

Old forum URL: forums.lhotka.net/forums/t/5537.aspx


rkelley posted on Monday, October 06, 2008

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

RockfordLhotka replied on Monday, October 06, 2008

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.

rkelley replied on Monday, October 06, 2008

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

RockfordLhotka replied on Monday, October 06, 2008

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

 

rkelley replied on Monday, October 06, 2008

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.

RockfordLhotka replied on Monday, October 06, 2008

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 replied on Monday, October 06, 2008

I went down the path of creating a Generic Factory for the ObjectFactory, simply because I wanted to deal with Concrete types and interfaces to simplify testing and Mocking.  And also I did not want to be in position to create one factory per each BO as well as not wanting to duplicate Rocky's before-mentioned implementation.

What I soon discovered was that if I go down the route of generics I will need one factory par one Csla type (one for ReadOnlyList, one for EditableRoot, etc).

Also I discovered that I need to pass the "Generic Factory", concrete types that I want constructed, like ReadOnlyList, for example, needs a Csla List object - ProjectList and also ReadOnly Item type - ProjectInfo for example. 

That meant changing the ObjectFactory attribute to accept that, something like:
[ObjectFactory("Factory Type=ReadOnlyListServerFactory;List Type=ExtJsCslaDemo.Lib.CustomerList, ExtJsCslaDemo.Lib;Item Type=ExtJsCslaDemo.Lib.CustomerInfo, ExtJsCslaDemo.Lib;DTO Type=Northwind.Data.Customers, Northwind.Data")]

You can see that besides the 2 before mentioned types - I am also passing the DTO type - So my Generic Factory would be aware of DTO object used to populate the Csla List Object, as well as object implementing IRepository interface.  The reason for that is having Factory inject all of the dependencies needed for Fetch and Create, and leaving that decision to Factory.  The IRepository<T> where T is the DTO send to the Fetch is definded as:
  public interface IRepository<T>
  {
    IQueryable<T> GetAll();
  }

The nice thing about that part was that Repositories are used to hide the Linq/Entity Framework implementation from the Business Layer, but still since we return the IQueriable, we still have the full advantage of Linq.  In adition to that as the whole DAL is represented by a single interface with a single method it is very easy to come up with test scenarios where we can send the MockRepository instead of going against the database.

In order to implement a scenario of more than one Generic Factory (one per Csla base type), I needed to override besides the ObjectFactory also a FactoryLoader.  Here is my custom implementation:
  public class GenericFactoryLoader : IObjectFactoryLoader
  {
    #region Constructor

    private readonly IFactoryLoaderConfigParser parser;

    public GenericFactoryLoader():this(new GenericFactoryLoaderAttributeParser())
    {
    }
    public GenericFactoryLoader(IFactoryLoaderConfigParser parser)
    {
      this.parser = parser;
    }

    #endregion


    public virtual Type GetFactoryType(string factoryConnectionString)
    {
      if(factoryConnectionString==null)
        throw new ArgumentNullException("factoryConnectionString");

      parser.Parse(factoryConnectionString);

      var factoryTypeName = parser.FactoryType;

      if(factoryTypeName=="ReadOnlyListServerFactory")
      {
        var generic = typeof (ReadOnlyListServerFactory<,,>);

        Type[] typeArgs = {Type.GetType(parser.ListType), Type.GetType(parser.ItemType), Type.GetType(parser.DTOType) };

        var constructed = generic.MakeGenericType(typeArgs);

        return constructed;
      }
       
      throw new UnkownFactoryTypeArgumentException();

    }

    public virtual object GetFactory(string factoryName)
    {
      var factoryType = GetFactoryType(factoryName);

      if (factoryType == null)
        throw new InvalidOperationException(
          string.Format("Factory Type Not Found: {0}", factoryName));

      return
        factoryType.GetGenericTypeDefinition() == typeof(ReadOnlyListServerFactory<,,>) ?
          Activator.CreateInstance(factoryType, new object[] {Activator.CreateInstance(Type.GetType(parser.RepositoryType))}) :
          Activator.CreateInstance(factoryType);
    }
  }


So basically the FactoryLoader has to implement those 2 methods GetFactoryType() and GetFactory().  In this  case you see that the GenericFactoryLoader accepts a ObjectFactoryAttribute values mentioned above and passes it to an object called GenericFactoryLoaderAttributeParser, which parses the values and returns to the loader type of factory, as well as Csla Types that need to be passed to that Generic Factory.

So finally bellow is an initial implementation of GenericReadOnlyListFactory as an example of my ObjectFactory implementation - factory by default implements the Fetch, Create,Delete,Update - and those are the default names for the ObjectFactory methods used for those operations:

  /// <typeparam name="L">Csla ROL type</typeparam>
  /// <typeparam name="I">Csla ROL item type</typeparam>
  /// <typeparam name="R">DTO type returned by IRepository</typeparam>
  public class ReadOnlyListServerFactory<L, I, R> :
    AbstractServerBusinessFactory<L>
    where L : ReadOnlyListBase<L, I>, new()
   
  {
    private readonly IRepository<R> repository;
    public ReadOnlyListServerFactory(IRepository<R> repository)
    {
      this.repository = repository;
    }
 
     ...

    public override L Create(SingleCriteria<L, int> criteria)
    {
      throw new NotImplementedException();
    }

    public override L Fetch()
    {
      var list = new L();
      var canFetchAll = (ICanFetchAll<R>) list;

      list.RaiseListChangedEvents = false;

      canFetchAll.FetchAll(repository);

      list.RaiseListChangedEvents = true;

      return list;
    }

    public override L Fetch(CriteriaBase criteria)
    {
      var t = new L();
      var canFetchBy = (ICanFetchWitCriteria<R>) t;


      t.RaiseListChangedEvents = false;

      canFetchBy.FetchBy(repository,criteria);

      t.RaiseListChangedEvents = true;
      return t;
    }


As you can see the Generic Object Factory above actually passes the IRepository<T> to the Csla object, but it aslo requires the object to implement ICanFetch<R> interface if call comes from parameterless Object Factory Fetch(), or ICanFetchWithCriteria<R>.

So finally here is an example of an object that is called by that Factory:

  [ObjectFactory("Factory Type=ReadOnlyListServerFactory;List Type=ExtJsCslaDemo.Lib.CustomerList, ExtJsCslaDemo.Lib;Item Type=ExtJsCslaDemo.Lib.CustomerInfo, ExtJsCslaDemo.Lib;DTO Type=Northwind.Data.Customers, Northwind.Data;Repository Type=Northwind.Data.SqlCustomerRepository, Northwind.Data")]
  [Serializable]
  public class CustomerList : ReadOnlyListBase<CustomerList, CustomerInfo>, ICanFetchAll<Customers>
  {
    #region Data Access

    public void FetchAll(IRepository<Customers> customersRepository)
    {
      var customers =
        from customer in customersRepository.GetAll()
        select customer;

      IsReadOnly = false;
      foreach(var customer in customers)
        Add(new CustomerInfo(customer));
      IsReadOnly = true;
    }

    #endregion


So as you can see - a lot of work, perhaps too much, but it turns the Csla object into Unit Test "friendly" object, and the actual CustomerList implementation is quite simple.  Is it worth it - I leave that up to you.
  public interface ICanFetchAll<T>
  {
    void FetchAll(IRepository<T> repository);
  }

  public interface ICanFetchWitCriteria<T> :ICanFetchAll<T>
  {
    void FetchBy(IRepository<T> repository, CriteriaBase criteria);
    //void Fetch(SingleCriteria<L, int> criteria);
  }

  public interface ICanCreate
  {
    void Create();
  }


rkelley replied on Monday, October 06, 2008

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.

nermin replied on Monday, October 06, 2008

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.



FrankM replied on Monday, October 06, 2008

StructureMap is great for unit-test CSLA, we are using it right now and enjoy it very much. The inject method is so amazing. The only drawback might be lack of documents.

rkelley replied on Tuesday, October 07, 2008

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

nermin replied on Tuesday, October 07, 2008

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



rkelley replied on Tuesday, October 07, 2008

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?

FrankM replied on Tuesday, October 07, 2008

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.

nermin replied on Tuesday, October 07, 2008

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.


RockfordLhotka replied on Tuesday, October 07, 2008

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:

  1. Physical database (tables, indexes, etc)
  2. Logical database (logical data shape, views, sprocs)
  3. Database vendor (SQL dialect, etc)
  4. Data access technology (ADO.NET)
  5. Abstraction technology (DataSet, L2S, EF, NHibernate)

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.

FrankM replied on Tuesday, October 07, 2008

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.

nermin replied on Tuesday, October 07, 2008

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.


FrankM replied on Tuesday, October 07, 2008

Just one more DTO class then you gain the pure isolation from data access tech, I think it's worth to do it. And, if using code gen, this won't be a problem at all.

rkelley replied on Thursday, October 09, 2008

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;
        }

rkelley replied on Sunday, October 19, 2008

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:

http://cslaptrackerfactory.googlecode.com

Kevin Fairclough replied on Monday, November 16, 2009

We are using this (or at least a flavour of it) for our project. 

Currently we are experiencing strange errors when calling the DataPortal using async calls (from a WPF gui ).  Can anyone give us some clues to why this might be.  Our GenericFactoryLoader class is not static, however we do have a static constructor to do the initialisation of StructureMap.

Any help would be greatly appreciated.

Kevin

RockfordLhotka replied on Monday, November 16, 2009

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.

nermin replied on Tuesday, October 07, 2008

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?



RockfordLhotka replied on Tuesday, October 07, 2008

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

 

RockfordLhotka replied on Monday, October 06, 2008

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