|
I've deprecated findByAnd locally, replacing calls with a variant that
takes a boolean, which specifies whether to use the cache. Initially, my replacement just added a new findByAnd. However, I'm now starting to lean towards replacing with findList instead. However, in my opinion, I think that will make programming ofbiz more difficult. I'd like to add a findList variant, that takes a Map instead of an EntityCondition. Without this new variant, there would be ton of variants that would only need to import EntityCondition, just to create a condition. There are also performance considerations to consider. EntityCondition.makeCondition(Map) directly takes the map, doing no processing. However, EntityCondition.makeCondition(Object...) eventually calls EntityUtil.makeFields, which does a little more than UtilMisc. In addition to the iteration over the array, it also does a check on the value for Comparable/Serializable. This latter check seems a bit superfluous, as eventually the base condition classes check the values against the model. So, from a purist stand point, even tho findByAnd could be replaced by findList, I think it is too useful; it saves enough code in application layers, imho. |
|
Yes, exactly, this is why it wasn't deprecated with the big culling a while back. -David On Dec 7, 2010, at 8:29 AM, Adam Heath wrote: > I've deprecated findByAnd locally, replacing calls with a variant that > takes a boolean, which specifies whether to use the cache. > > Initially, my replacement just added a new findByAnd. However, I'm > now starting to lean towards replacing with findList instead. > However, in my opinion, I think that will make programming ofbiz more > difficult. > > I'd like to add a findList variant, that takes a Map instead of an > EntityCondition. Without this new variant, there would be ton of > variants that would only need to import EntityCondition, just to > create a condition. > > There are also performance considerations to consider. > > EntityCondition.makeCondition(Map) directly takes the map, doing no > processing. However, EntityCondition.makeCondition(Object...) > eventually calls EntityUtil.makeFields, which does a little more than > UtilMisc. In addition to the iteration over the array, it also does a > check on the value for Comparable/Serializable. This latter check > seems a bit superfluous, as eventually the base condition classes > check the values against the model. > > So, from a purist stand point, even tho findByAnd could be replaced by > findList, I think it is too useful; it saves enough code in > application layers, imho. > |
|
In reply to this post by Adam Heath-2
On 8/12/2010, at 4:29 AM, Adam Heath wrote:
> I've deprecated findByAnd locally, replacing calls with a variant that > takes a boolean, which specifies whether to use the cache. > > Initially, my replacement just added a new findByAnd. However, I'm > now starting to lean towards replacing with findList instead. > However, in my opinion, I think that will make programming ofbiz more > difficult. > > I'd like to add a findList variant, that takes a Map instead of an > EntityCondition. Without this new variant, there would be ton of > variants that would only need to import EntityCondition, just to > create a condition. > > There are also performance considerations to consider. > > EntityCondition.makeCondition(Map) directly takes the map, doing no > processing. However, EntityCondition.makeCondition(Object...) > eventually calls EntityUtil.makeFields, which does a little more than > UtilMisc. In addition to the iteration over the array, it also does a > check on the value for Comparable/Serializable. This latter check > seems a bit superfluous, as eventually the base condition classes > check the values against the model. > > So, from a purist stand point, even tho findByAnd could be replaced by > findList, I think it is too useful; it saves enough code in > application layers, imho. > Here are some examples: thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); // becomes thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); List productNodesList = delegator.findByAndCache("ProductAssoc", UtilMisc.toMap("productIdTo", productId, "productAssocTypeId", bomType)); productNodesList = EntityUtil.filterByDate(productNodesList, inDate); // becomes List productNodesList = EntityList.query(delegator).from("ProductAssoc").where("productIdTo", productId, "productAssocTypeId", bomType).cache().filterByDate().list(); List<GenericValue> inventoryItems = delegator.findByAnd("InventoryItem", ecl, null, null, null, false); // becomes List<GenericValue> inventoryItems = EntityList.query(delegator).from("InventoryItem").where(ecl).list(); // all this (long winded example) EntityFindOptions efo = new EntityFindOptions(); efo.setDistinct(true); efo.setResultSetType(EntityFindOptions.TYPE_SCROLL_INSENSITIVE); if (maxResults != null) { efo.setMaxRows(maxResults); } eli = delegator.findListIteratorByCondition(dynamicViewEntity, whereCondition, null, fieldsToSelect, orderByList, efo); // becomes eli = EntityList.query(delegator).from(dynamicViewEntity).where(whereCondition).select(fieldsToSelect).orderBy(orderByList).distinct().cursorScrollInsensitive().maxRows(maxResults).iterator(); They aren't necessarily shorter, but they are easier to write, easier to read and would be easier to remember (for things like groovy). Regards Scott HotWax Media http://www.hotwaxmedia.com |
|
Anything that makes Java/Groovy more fluent will get a big +1 from me.
-Adrian On 12/8/2010 1:00 PM, Scott Gray wrote: > On 8/12/2010, at 4:29 AM, Adam Heath wrote: > >> I've deprecated findByAnd locally, replacing calls with a variant that >> takes a boolean, which specifies whether to use the cache. >> >> Initially, my replacement just added a new findByAnd. However, I'm >> now starting to lean towards replacing with findList instead. >> However, in my opinion, I think that will make programming ofbiz more >> difficult. >> >> I'd like to add a findList variant, that takes a Map instead of an >> EntityCondition. Without this new variant, there would be ton of >> variants that would only need to import EntityCondition, just to >> create a condition. >> >> There are also performance considerations to consider. >> >> EntityCondition.makeCondition(Map) directly takes the map, doing no >> processing. However, EntityCondition.makeCondition(Object...) >> eventually calls EntityUtil.makeFields, which does a little more than >> UtilMisc. In addition to the iteration over the array, it also does a >> check on the value for Comparable/Serializable. This latter check >> seems a bit superfluous, as eventually the base condition classes >> check the values against the model. >> >> So, from a purist stand point, even tho findByAnd could be replaced by >> findList, I think it is too useful; it saves enough code in >> application layers, imho. >> > > This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. > > Here are some examples: > thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); > // becomes > thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); > > List productNodesList = delegator.findByAndCache("ProductAssoc", UtilMisc.toMap("productIdTo", productId, "productAssocTypeId", bomType)); > productNodesList = EntityUtil.filterByDate(productNodesList, inDate); > // becomes > List productNodesList = EntityList.query(delegator).from("ProductAssoc").where("productIdTo", productId, "productAssocTypeId", bomType).cache().filterByDate().list(); > > List<GenericValue> inventoryItems = delegator.findByAnd("InventoryItem", ecl, null, null, null, false); > // becomes > List<GenericValue> inventoryItems = EntityList.query(delegator).from("InventoryItem").where(ecl).list(); > > // all this (long winded example) > EntityFindOptions efo = new EntityFindOptions(); > efo.setDistinct(true); > efo.setResultSetType(EntityFindOptions.TYPE_SCROLL_INSENSITIVE); > if (maxResults != null) { > efo.setMaxRows(maxResults); > } > eli = delegator.findListIteratorByCondition(dynamicViewEntity, whereCondition, null, fieldsToSelect, orderByList, efo); > // becomes > eli = EntityList.query(delegator).from(dynamicViewEntity).where(whereCondition).select(fieldsToSelect).orderBy(orderByList).distinct().cursorScrollInsensitive().maxRows(maxResults).iterator(); > > They aren't necessarily shorter, but they are easier to write, easier to read and would be easier to remember (for things like groovy). > > Regards > Scott > > HotWax Media > http://www.hotwaxmedia.com > |
|
Administrator
|
I like the chaining stuff, I have always loved function composition, in computing also
Jacques From: "Adrian Crum" <[hidden email]> > Anything that makes Java/Groovy more fluent will get a big +1 from me. > > -Adrian > > On 12/8/2010 1:00 PM, Scott Gray wrote: >> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >> >>> I've deprecated findByAnd locally, replacing calls with a variant that >>> takes a boolean, which specifies whether to use the cache. >>> >>> Initially, my replacement just added a new findByAnd. However, I'm >>> now starting to lean towards replacing with findList instead. >>> However, in my opinion, I think that will make programming ofbiz more >>> difficult. >>> >>> I'd like to add a findList variant, that takes a Map instead of an >>> EntityCondition. Without this new variant, there would be ton of >>> variants that would only need to import EntityCondition, just to >>> create a condition. >>> >>> There are also performance considerations to consider. >>> >>> EntityCondition.makeCondition(Map) directly takes the map, doing no >>> processing. However, EntityCondition.makeCondition(Object...) >>> eventually calls EntityUtil.makeFields, which does a little more than >>> UtilMisc. In addition to the iteration over the array, it also does a >>> check on the value for Comparable/Serializable. This latter check >>> seems a bit superfluous, as eventually the base condition classes >>> check the values against the model. >>> >>> So, from a purist stand point, even tho findByAnd could be replaced by >>> findList, I think it is too useful; it saves enough code in >>> application layers, imho. >>> >> >> This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. >> >> Here are some examples: >> thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); >> // becomes >> thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); >> >> List productNodesList = delegator.findByAndCache("ProductAssoc", UtilMisc.toMap("productIdTo", productId, "productAssocTypeId", >> bomType)); >> productNodesList = EntityUtil.filterByDate(productNodesList, inDate); >> // becomes >> List productNodesList = EntityList.query(delegator).from("ProductAssoc").where("productIdTo", productId, "productAssocTypeId", >> bomType).cache().filterByDate().list(); >> >> List<GenericValue> inventoryItems = delegator.findByAnd("InventoryItem", ecl, null, null, null, false); >> // becomes >> List<GenericValue> inventoryItems = EntityList.query(delegator).from("InventoryItem").where(ecl).list(); >> >> // all this (long winded example) >> EntityFindOptions efo = new EntityFindOptions(); >> efo.setDistinct(true); >> efo.setResultSetType(EntityFindOptions.TYPE_SCROLL_INSENSITIVE); >> if (maxResults != null) { >> efo.setMaxRows(maxResults); >> } >> eli = delegator.findListIteratorByCondition(dynamicViewEntity, whereCondition, null, fieldsToSelect, orderByList, efo); >> // becomes >> eli = >> EntityList.query(delegator).from(dynamicViewEntity).where(whereCondition).select(fieldsToSelect).orderBy(orderByList).distinct().cursorScrollInsensitive().maxRows(maxResults).iterator(); >> >> They aren't necessarily shorter, but they are easier to write, easier to read and would be easier to remember (for things like >> groovy). >> >> Regards >> Scott >> >> HotWax Media >> http://www.hotwaxmedia.com >> > |
|
In reply to this post by Scott Gray-2
On 12/08/2010 03:00 PM, Scott Gray wrote:
> On 8/12/2010, at 4:29 AM, Adam Heath wrote: > >> I've deprecated findByAnd locally, replacing calls with a variant that >> takes a boolean, which specifies whether to use the cache. >> >> Initially, my replacement just added a new findByAnd. However, I'm >> now starting to lean towards replacing with findList instead. >> However, in my opinion, I think that will make programming ofbiz more >> difficult. >> >> I'd like to add a findList variant, that takes a Map instead of an >> EntityCondition. Without this new variant, there would be ton of >> variants that would only need to import EntityCondition, just to >> create a condition. >> >> There are also performance considerations to consider. >> >> EntityCondition.makeCondition(Map) directly takes the map, doing no >> processing. However, EntityCondition.makeCondition(Object...) >> eventually calls EntityUtil.makeFields, which does a little more than >> UtilMisc. In addition to the iteration over the array, it also does a >> check on the value for Comparable/Serializable. This latter check >> seems a bit superfluous, as eventually the base condition classes >> check the values against the model. >> >> So, from a purist stand point, even tho findByAnd could be replaced by >> findList, I think it is too useful; it saves enough code in >> application layers, imho. >> > > This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. > > Here are some examples: > thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); > // becomes > thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); api: EntityOne(delegator).from().... in foo.groovy: use(DelegatorCategory) { } class DelegatorCategory { public static EntityOneBuilder EntityOne(Delegator delegator) { return new EntityOneBuilder(delegator); } } class EntityOneBuilder { public EntityOneBuilder from(String entityName) { return this; } public GenericValue query() { return delegator.findOne(....); } } This is almost like what you suggested, but it removes the query() method that starts thte builder, and changes the find() to query(). EntityList would be done the same one. The way you have it, is that the start(EntityOne, EntityList) and the end(find(), list()), are 2 things that have to be remembered. My version just has one thing(the start of the call). > > List productNodesList = delegator.findByAndCache("ProductAssoc", UtilMisc.toMap("productIdTo", productId, "productAssocTypeId", bomType)); > productNodesList = EntityUtil.filterByDate(productNodesList, inDate); > // becomes > List productNodesList = EntityList.query(delegator).from("ProductAssoc").where("productIdTo", productId, "productAssocTypeId", bomType).cache().filterByDate().list(); > > List<GenericValue> inventoryItems = delegator.findByAnd("InventoryItem", ecl, null, null, null, false); > // becomes > List<GenericValue> inventoryItems = EntityList.query(delegator).from("InventoryItem").where(ecl).list(); > > // all this (long winded example) > EntityFindOptions efo = new EntityFindOptions(); > efo.setDistinct(true); > efo.setResultSetType(EntityFindOptions.TYPE_SCROLL_INSENSITIVE); > if (maxResults != null) { > efo.setMaxRows(maxResults); > } > eli = delegator.findListIteratorByCondition(dynamicViewEntity, whereCondition, null, fieldsToSelect, orderByList, efo); > // becomes > eli = EntityList.query(delegator).from(dynamicViewEntity).where(whereCondition).select(fieldsToSelect).orderBy(orderByList).distinct().cursorScrollInsensitive().maxRows(maxResults).iterator(); > > They aren't necessarily shorter, but they are easier to write, easier to read and would be easier to remember (for things like groovy). > > Regards > Scott > > HotWax Media > http://www.hotwaxmedia.com > |
|
On 9/12/2010, at 11:50 AM, Adam Heath wrote:
> On 12/08/2010 03:00 PM, Scott Gray wrote: >> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >> >>> I've deprecated findByAnd locally, replacing calls with a variant that >>> takes a boolean, which specifies whether to use the cache. >>> >>> Initially, my replacement just added a new findByAnd. However, I'm >>> now starting to lean towards replacing with findList instead. >>> However, in my opinion, I think that will make programming ofbiz more >>> difficult. >>> >>> I'd like to add a findList variant, that takes a Map instead of an >>> EntityCondition. Without this new variant, there would be ton of >>> variants that would only need to import EntityCondition, just to >>> create a condition. >>> >>> There are also performance considerations to consider. >>> >>> EntityCondition.makeCondition(Map) directly takes the map, doing no >>> processing. However, EntityCondition.makeCondition(Object...) >>> eventually calls EntityUtil.makeFields, which does a little more than >>> UtilMisc. In addition to the iteration over the array, it also does a >>> check on the value for Comparable/Serializable. This latter check >>> seems a bit superfluous, as eventually the base condition classes >>> check the values against the model. >>> >>> So, from a purist stand point, even tho findByAnd could be replaced by >>> findList, I think it is too useful; it saves enough code in >>> application layers, imho. >>> >> >> This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. >> >> Here are some examples: >> thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); >> // becomes >> thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); > > api: > EntityOne(delegator).from().... > > in foo.groovy: > use(DelegatorCategory) { > > } > > class DelegatorCategory { > public static EntityOneBuilder EntityOne(Delegator delegator) { > return new EntityOneBuilder(delegator); > } > } > class EntityOneBuilder { > public EntityOneBuilder from(String entityName) { > return this; > } > > public GenericValue query() { > return delegator.findOne(....); > } > } > > This is almost like what you suggested, but it removes the query() method that starts thte builder, and changes the find() to query(). > > EntityList would be done the same one. > > The way you have it, is that the start(EntityOne, EntityList) and the end(find(), list()), are 2 things that have to be remembered. My version just has one thing(the start of the call). Also EntityList's execute methods so far are: list() iterator() first() count() I'm trying to cover everything the delegator does for SELECTs and a bit of the more common EntityUtil methods within those two Entity* classes. With some good javadocs I think it will work pretty well. Regards Scott |
|
In reply to this post by Scott Gray-2
Cool!
Jacopo On Dec 8, 2010, at 10:00 PM, Scott Gray wrote: > On 8/12/2010, at 4:29 AM, Adam Heath wrote: > >> I've deprecated findByAnd locally, replacing calls with a variant that >> takes a boolean, which specifies whether to use the cache. >> >> Initially, my replacement just added a new findByAnd. However, I'm >> now starting to lean towards replacing with findList instead. >> However, in my opinion, I think that will make programming ofbiz more >> difficult. >> >> I'd like to add a findList variant, that takes a Map instead of an >> EntityCondition. Without this new variant, there would be ton of >> variants that would only need to import EntityCondition, just to >> create a condition. >> >> There are also performance considerations to consider. >> >> EntityCondition.makeCondition(Map) directly takes the map, doing no >> processing. However, EntityCondition.makeCondition(Object...) >> eventually calls EntityUtil.makeFields, which does a little more than >> UtilMisc. In addition to the iteration over the array, it also does a >> check on the value for Comparable/Serializable. This latter check >> seems a bit superfluous, as eventually the base condition classes >> check the values against the model. >> >> So, from a purist stand point, even tho findByAnd could be replaced by >> findList, I think it is too useful; it saves enough code in >> application layers, imho. >> > > This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. > > Here are some examples: > thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); > // becomes > thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); > > List productNodesList = delegator.findByAndCache("ProductAssoc", UtilMisc.toMap("productIdTo", productId, "productAssocTypeId", bomType)); > productNodesList = EntityUtil.filterByDate(productNodesList, inDate); > // becomes > List productNodesList = EntityList.query(delegator).from("ProductAssoc").where("productIdTo", productId, "productAssocTypeId", bomType).cache().filterByDate().list(); > > List<GenericValue> inventoryItems = delegator.findByAnd("InventoryItem", ecl, null, null, null, false); > // becomes > List<GenericValue> inventoryItems = EntityList.query(delegator).from("InventoryItem").where(ecl).list(); > > // all this (long winded example) > EntityFindOptions efo = new EntityFindOptions(); > efo.setDistinct(true); > efo.setResultSetType(EntityFindOptions.TYPE_SCROLL_INSENSITIVE); > if (maxResults != null) { > efo.setMaxRows(maxResults); > } > eli = delegator.findListIteratorByCondition(dynamicViewEntity, whereCondition, null, fieldsToSelect, orderByList, efo); > // becomes > eli = EntityList.query(delegator).from(dynamicViewEntity).where(whereCondition).select(fieldsToSelect).orderBy(orderByList).distinct().cursorScrollInsensitive().maxRows(maxResults).iterator(); > > They aren't necessarily shorter, but they are easier to write, easier to read and would be easier to remember (for things like groovy). > > Regards > Scott > > HotWax Media > http://www.hotwaxmedia.com > |
|
In reply to this post by Scott Gray-2
On 12/09/2010 12:03 AM, Scott Gray wrote:
> On 9/12/2010, at 11:50 AM, Adam Heath wrote: > >> On 12/08/2010 03:00 PM, Scott Gray wrote: >>> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >>> >>>> I've deprecated findByAnd locally, replacing calls with a variant that >>>> takes a boolean, which specifies whether to use the cache. >>>> >>>> Initially, my replacement just added a new findByAnd. However, I'm >>>> now starting to lean towards replacing with findList instead. >>>> However, in my opinion, I think that will make programming ofbiz more >>>> difficult. >>>> >>>> I'd like to add a findList variant, that takes a Map instead of an >>>> EntityCondition. Without this new variant, there would be ton of >>>> variants that would only need to import EntityCondition, just to >>>> create a condition. >>>> >>>> There are also performance considerations to consider. >>>> >>>> EntityCondition.makeCondition(Map) directly takes the map, doing no >>>> processing. However, EntityCondition.makeCondition(Object...) >>>> eventually calls EntityUtil.makeFields, which does a little more than >>>> UtilMisc. In addition to the iteration over the array, it also does a >>>> check on the value for Comparable/Serializable. This latter check >>>> seems a bit superfluous, as eventually the base condition classes >>>> check the values against the model. >>>> >>>> So, from a purist stand point, even tho findByAnd could be replaced by >>>> findList, I think it is too useful; it saves enough code in >>>> application layers, imho. >>>> >>> >>> This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. >>> >>> Here are some examples: >>> thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); >>> // becomes >>> thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); >> >> api: >> EntityOne(delegator).from().... >> >> in foo.groovy: >> use(DelegatorCategory) { >> >> } >> >> class DelegatorCategory { >> public static EntityOneBuilder EntityOne(Delegator delegator) { >> return new EntityOneBuilder(delegator); >> } >> } >> class EntityOneBuilder { >> public EntityOneBuilder from(String entityName) { >> return this; >> } >> >> public GenericValue query() { >> return delegator.findOne(....); >> } >> } >> >> This is almost like what you suggested, but it removes the query() method that starts thte builder, and changes the find() to query(). >> >> EntityList would be done the same one. >> >> The way you have it, is that the start(EntityOne, EntityList) and the end(find(), list()), are 2 things that have to be remembered. My version just has one thing(the start of the call). > > This is all groovy DSL related though right? I hadn't worried about groovy too much because I knew we had a fair bit of flexibility thanks to the language features. The API I've written to date was solely intended for java development but seems succinct enough that not much would need to change for groovy. > > Also EntityList's execute methods so far are: > list() > iterator() > first() > count() All primary methods should be query(), imho. interface GenericQueryBuilder<T> { T query(); } public class EntityOne implements GenericQueryBuilder<GenericValue> { public GenericValue query() {} } public class EntityList implements GenericQueryBuilder<List<GenericValue>>, Iterable<GenericValue> { public List<GenericValue> query() {} public Iterator<GenericValue> iterator() {} ... } |
|
On 10/12/2010, at 5:53 AM, Adam Heath wrote:
> On 12/09/2010 12:03 AM, Scott Gray wrote: >> On 9/12/2010, at 11:50 AM, Adam Heath wrote: >> >>> On 12/08/2010 03:00 PM, Scott Gray wrote: >>>> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >>>> >>>>> I've deprecated findByAnd locally, replacing calls with a variant that >>>>> takes a boolean, which specifies whether to use the cache. >>>>> >>>>> Initially, my replacement just added a new findByAnd. However, I'm >>>>> now starting to lean towards replacing with findList instead. >>>>> However, in my opinion, I think that will make programming ofbiz more >>>>> difficult. >>>>> >>>>> I'd like to add a findList variant, that takes a Map instead of an >>>>> EntityCondition. Without this new variant, there would be ton of >>>>> variants that would only need to import EntityCondition, just to >>>>> create a condition. >>>>> >>>>> There are also performance considerations to consider. >>>>> >>>>> EntityCondition.makeCondition(Map) directly takes the map, doing no >>>>> processing. However, EntityCondition.makeCondition(Object...) >>>>> eventually calls EntityUtil.makeFields, which does a little more than >>>>> UtilMisc. In addition to the iteration over the array, it also does a >>>>> check on the value for Comparable/Serializable. This latter check >>>>> seems a bit superfluous, as eventually the base condition classes >>>>> check the values against the model. >>>>> >>>>> So, from a purist stand point, even tho findByAnd could be replaced by >>>>> findList, I think it is too useful; it saves enough code in >>>>> application layers, imho. >>>>> >>>> >>>> This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. >>>> >>>> Here are some examples: >>>> thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); >>>> // becomes >>>> thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); >>> >>> api: >>> EntityOne(delegator).from().... >>> >>> in foo.groovy: >>> use(DelegatorCategory) { >>> >>> } >>> >>> class DelegatorCategory { >>> public static EntityOneBuilder EntityOne(Delegator delegator) { >>> return new EntityOneBuilder(delegator); >>> } >>> } >>> class EntityOneBuilder { >>> public EntityOneBuilder from(String entityName) { >>> return this; >>> } >>> >>> public GenericValue query() { >>> return delegator.findOne(....); >>> } >>> } >>> >>> This is almost like what you suggested, but it removes the query() method that starts thte builder, and changes the find() to query(). >>> >>> EntityList would be done the same one. >>> >>> The way you have it, is that the start(EntityOne, EntityList) and the end(find(), list()), are 2 things that have to be remembered. My version just has one thing(the start of the call). >> >> This is all groovy DSL related though right? I hadn't worried about groovy too much because I knew we had a fair bit of flexibility thanks to the language features. The API I've written to date was solely intended for java development but seems succinct enough that not much would need to change for groovy. >> >> Also EntityList's execute methods so far are: >> list() >> iterator() >> first() >> count() > > All primary methods should be query(), imho. > > interface GenericQueryBuilder<T> { > T query(); > } > > public class EntityOne implements GenericQueryBuilder<GenericValue> { > public GenericValue query() {} > } > > public class EntityList implements GenericQueryBuilder<List<GenericValue>>, Iterable<GenericValue> { > public List<GenericValue> query() {} > public Iterator<GenericValue> iterator() {} > ... > } Regards Scott |
|
On 12/09/2010 01:48 PM, Scott Gray wrote:
> On 10/12/2010, at 5:53 AM, Adam Heath wrote: > >> On 12/09/2010 12:03 AM, Scott Gray wrote: >>> On 9/12/2010, at 11:50 AM, Adam Heath wrote: >>> >>>> On 12/08/2010 03:00 PM, Scott Gray wrote: >>>>> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >>>>> >>>>>> I've deprecated findByAnd locally, replacing calls with a variant that >>>>>> takes a boolean, which specifies whether to use the cache. >>>>>> >>>>>> Initially, my replacement just added a new findByAnd. However, I'm >>>>>> now starting to lean towards replacing with findList instead. >>>>>> However, in my opinion, I think that will make programming ofbiz more >>>>>> difficult. >>>>>> >>>>>> I'd like to add a findList variant, that takes a Map instead of an >>>>>> EntityCondition. Without this new variant, there would be ton of >>>>>> variants that would only need to import EntityCondition, just to >>>>>> create a condition. >>>>>> >>>>>> There are also performance considerations to consider. >>>>>> >>>>>> EntityCondition.makeCondition(Map) directly takes the map, doing no >>>>>> processing. However, EntityCondition.makeCondition(Object...) >>>>>> eventually calls EntityUtil.makeFields, which does a little more than >>>>>> UtilMisc. In addition to the iteration over the array, it also does a >>>>>> check on the value for Comparable/Serializable. This latter check >>>>>> seems a bit superfluous, as eventually the base condition classes >>>>>> check the values against the model. >>>>>> >>>>>> So, from a purist stand point, even tho findByAnd could be replaced by >>>>>> findList, I think it is too useful; it saves enough code in >>>>>> application layers, imho. >>>>>> >>>>> >>>>> This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. >>>>> >>>>> Here are some examples: >>>>> thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); >>>>> // becomes >>>>> thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); >>>> >>>> api: >>>> EntityOne(delegator).from().... >>>> >>>> in foo.groovy: >>>> use(DelegatorCategory) { >>>> >>>> } >>>> >>>> class DelegatorCategory { >>>> public static EntityOneBuilder EntityOne(Delegator delegator) { >>>> return new EntityOneBuilder(delegator); >>>> } >>>> } >>>> class EntityOneBuilder { >>>> public EntityOneBuilder from(String entityName) { >>>> return this; >>>> } >>>> >>>> public GenericValue query() { >>>> return delegator.findOne(....); >>>> } >>>> } >>>> >>>> This is almost like what you suggested, but it removes the query() method that starts thte builder, and changes the find() to query(). >>>> >>>> EntityList would be done the same one. >>>> >>>> The way you have it, is that the start(EntityOne, EntityList) and the end(find(), list()), are 2 things that have to be remembered. My version just has one thing(the start of the call). >>> >>> This is all groovy DSL related though right? I hadn't worried about groovy too much because I knew we had a fair bit of flexibility thanks to the language features. The API I've written to date was solely intended for java development but seems succinct enough that not much would need to change for groovy. >>> >>> Also EntityList's execute methods so far are: >>> list() >>> iterator() >>> first() >>> count() >> >> All primary methods should be query(), imho. >> >> interface GenericQueryBuilder<T> { >> T query(); >> } >> >> public class EntityOne implements GenericQueryBuilder<GenericValue> { >> public GenericValue query() {} >> } >> >> public class EntityList implements GenericQueryBuilder<List<GenericValue>>, Iterable<GenericValue> { >> public List<GenericValue> query() {} >> public Iterator<GenericValue> iterator() {} >> ... >> } > > I'm not opposed to that, but I'll need another method name for specifying the delegator. How about use(delegator)? public final class EntityBuilderUtil { public static EntityOne one(Delegator delegator) { return new EntityOne(delegator); } public static EntityList list(Delegator delegator) { return new EntityList(delegator); } } This also means that java api code only needs to import one class. Plus, if this class is used as a groovy category, then groovy code can do this: one(delegator).cache(true)..... As groovy will see one as a method call, taking a variable with type Delegator, and search all its categories to find a matching method. You'll get all things for free. |
|
On 10/12/2010, at 8:54 AM, Adam Heath wrote:
> On 12/09/2010 01:48 PM, Scott Gray wrote: >> On 10/12/2010, at 5:53 AM, Adam Heath wrote: >> >>> On 12/09/2010 12:03 AM, Scott Gray wrote: >>>> On 9/12/2010, at 11:50 AM, Adam Heath wrote: >>>> >>>>> On 12/08/2010 03:00 PM, Scott Gray wrote: >>>>>> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >>>>>> >>>>>>> I've deprecated findByAnd locally, replacing calls with a variant that >>>>>>> takes a boolean, which specifies whether to use the cache. >>>>>>> >>>>>>> Initially, my replacement just added a new findByAnd. However, I'm >>>>>>> now starting to lean towards replacing with findList instead. >>>>>>> However, in my opinion, I think that will make programming ofbiz more >>>>>>> difficult. >>>>>>> >>>>>>> I'd like to add a findList variant, that takes a Map instead of an >>>>>>> EntityCondition. Without this new variant, there would be ton of >>>>>>> variants that would only need to import EntityCondition, just to >>>>>>> create a condition. >>>>>>> >>>>>>> There are also performance considerations to consider. >>>>>>> >>>>>>> EntityCondition.makeCondition(Map) directly takes the map, doing no >>>>>>> processing. However, EntityCondition.makeCondition(Object...) >>>>>>> eventually calls EntityUtil.makeFields, which does a little more than >>>>>>> UtilMisc. In addition to the iteration over the array, it also does a >>>>>>> check on the value for Comparable/Serializable. This latter check >>>>>>> seems a bit superfluous, as eventually the base condition classes >>>>>>> check the values against the model. >>>>>>> >>>>>>> So, from a purist stand point, even tho findByAnd could be replaced by >>>>>>> findList, I think it is too useful; it saves enough code in >>>>>>> application layers, imho. >>>>>>> >>>>>> >>>>>> This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. >>>>>> >>>>>> Here are some examples: >>>>>> thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); >>>>>> // becomes >>>>>> thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); >>>>> >>>>> api: >>>>> EntityOne(delegator).from().... >>>>> >>>>> in foo.groovy: >>>>> use(DelegatorCategory) { >>>>> >>>>> } >>>>> >>>>> class DelegatorCategory { >>>>> public static EntityOneBuilder EntityOne(Delegator delegator) { >>>>> return new EntityOneBuilder(delegator); >>>>> } >>>>> } >>>>> class EntityOneBuilder { >>>>> public EntityOneBuilder from(String entityName) { >>>>> return this; >>>>> } >>>>> >>>>> public GenericValue query() { >>>>> return delegator.findOne(....); >>>>> } >>>>> } >>>>> >>>>> This is almost like what you suggested, but it removes the query() method that starts thte builder, and changes the find() to query(). >>>>> >>>>> EntityList would be done the same one. >>>>> >>>>> The way you have it, is that the start(EntityOne, EntityList) and the end(find(), list()), are 2 things that have to be remembered. My version just has one thing(the start of the call). >>>> >>>> This is all groovy DSL related though right? I hadn't worried about groovy too much because I knew we had a fair bit of flexibility thanks to the language features. The API I've written to date was solely intended for java development but seems succinct enough that not much would need to change for groovy. >>>> >>>> Also EntityList's execute methods so far are: >>>> list() >>>> iterator() >>>> first() >>>> count() >>> >>> All primary methods should be query(), imho. >>> >>> interface GenericQueryBuilder<T> { >>> T query(); >>> } >>> >>> public class EntityOne implements GenericQueryBuilder<GenericValue> { >>> public GenericValue query() {} >>> } >>> >>> public class EntityList implements GenericQueryBuilder<List<GenericValue>>, Iterable<GenericValue> { >>> public List<GenericValue> query() {} >>> public Iterator<GenericValue> iterator() {} >>> ... >>> } >> >> I'm not opposed to that, but I'll need another method name for specifying the delegator. How about use(delegator)? > > public final class EntityBuilderUtil { > public static EntityOne one(Delegator delegator) { > return new EntityOne(delegator); > } > > public static EntityList list(Delegator delegator) { > return new EntityList(delegator); > } > } > > This also means that java api code only needs to import one class. Plus, if this class is used as a groovy category, then groovy code can do this: > > one(delegator).cache(true)..... > > As groovy will see one as a method call, taking a variable with type Delegator, and search all its categories to find a matching method. You'll get all things for free. Thanks Scott |
|
HotWax Media http://www.hotwaxmedia.com On 10/12/2010, at 8:58 AM, Scott Gray wrote: > On 10/12/2010, at 8:54 AM, Adam Heath wrote: > >> On 12/09/2010 01:48 PM, Scott Gray wrote: >>> On 10/12/2010, at 5:53 AM, Adam Heath wrote: >>> >>>> On 12/09/2010 12:03 AM, Scott Gray wrote: >>>>> On 9/12/2010, at 11:50 AM, Adam Heath wrote: >>>>> >>>>>> On 12/08/2010 03:00 PM, Scott Gray wrote: >>>>>>> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >>>>>>> >>>>>>>> I've deprecated findByAnd locally, replacing calls with a variant that >>>>>>>> takes a boolean, which specifies whether to use the cache. >>>>>>>> >>>>>>>> Initially, my replacement just added a new findByAnd. However, I'm >>>>>>>> now starting to lean towards replacing with findList instead. >>>>>>>> However, in my opinion, I think that will make programming ofbiz more >>>>>>>> difficult. >>>>>>>> >>>>>>>> I'd like to add a findList variant, that takes a Map instead of an >>>>>>>> EntityCondition. Without this new variant, there would be ton of >>>>>>>> variants that would only need to import EntityCondition, just to >>>>>>>> create a condition. >>>>>>>> >>>>>>>> There are also performance considerations to consider. >>>>>>>> >>>>>>>> EntityCondition.makeCondition(Map) directly takes the map, doing no >>>>>>>> processing. However, EntityCondition.makeCondition(Object...) >>>>>>>> eventually calls EntityUtil.makeFields, which does a little more than >>>>>>>> UtilMisc. In addition to the iteration over the array, it also does a >>>>>>>> check on the value for Comparable/Serializable. This latter check >>>>>>>> seems a bit superfluous, as eventually the base condition classes >>>>>>>> check the values against the model. >>>>>>>> >>>>>>>> So, from a purist stand point, even tho findByAnd could be replaced by >>>>>>>> findList, I think it is too useful; it saves enough code in >>>>>>>> application layers, imho. >>>>>>>> >>>>>>> >>>>>>> This reminded me of the query objects with method chaining that I suggested a while back so I threw them together this morning. >>>>>>> >>>>>>> Here are some examples: >>>>>>> thisContent = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", assocContentId)); >>>>>>> // becomes >>>>>>> thisContent = EntityOne.query(delegator).from("Content").where("contentId", assocContentId).cache().find(); >>>>>> >>>>>> api: >>>>>> EntityOne(delegator).from().... >>>>>> >>>>>> in foo.groovy: >>>>>> use(DelegatorCategory) { >>>>>> >>>>>> } >>>>>> >>>>>> class DelegatorCategory { >>>>>> public static EntityOneBuilder EntityOne(Delegator delegator) { >>>>>> return new EntityOneBuilder(delegator); >>>>>> } >>>>>> } >>>>>> class EntityOneBuilder { >>>>>> public EntityOneBuilder from(String entityName) { >>>>>> return this; >>>>>> } >>>>>> >>>>>> public GenericValue query() { >>>>>> return delegator.findOne(....); >>>>>> } >>>>>> } >>>>>> >>>>>> This is almost like what you suggested, but it removes the query() method that starts thte builder, and changes the find() to query(). >>>>>> >>>>>> EntityList would be done the same one. >>>>>> >>>>>> The way you have it, is that the start(EntityOne, EntityList) and the end(find(), list()), are 2 things that have to be remembered. My version just has one thing(the start of the call). >>>>> >>>>> This is all groovy DSL related though right? I hadn't worried about groovy too much because I knew we had a fair bit of flexibility thanks to the language features. The API I've written to date was solely intended for java development but seems succinct enough that not much would need to change for groovy. >>>>> >>>>> Also EntityList's execute methods so far are: >>>>> list() >>>>> iterator() >>>>> first() >>>>> count() >>>> >>>> All primary methods should be query(), imho. >>>> >>>> interface GenericQueryBuilder<T> { >>>> T query(); >>>> } >>>> >>>> public class EntityOne implements GenericQueryBuilder<GenericValue> { >>>> public GenericValue query() {} >>>> } >>>> >>>> public class EntityList implements GenericQueryBuilder<List<GenericValue>>, Iterable<GenericValue> { >>>> public List<GenericValue> query() {} >>>> public Iterator<GenericValue> iterator() {} >>>> ... >>>> } >>> >>> I'm not opposed to that, but I'll need another method name for specifying the delegator. How about use(delegator)? >> >> public final class EntityBuilderUtil { >> public static EntityOne one(Delegator delegator) { >> return new EntityOne(delegator); >> } >> >> public static EntityList list(Delegator delegator) { >> return new EntityList(delegator); >> } >> } >> >> This also means that java api code only needs to import one class. Plus, if this class is used as a groovy category, then groovy code can do this: >> >> one(delegator).cache(true)..... >> >> As groovy will see one as a method call, taking a variable with type Delegator, and search all its categories to find a matching method. You'll get all things for free. > > Works for me. > > Thanks > Scott Regards Scott |
|
In reply to this post by Adam Heath-2
In the spirit of changing the entity/delegator interface more object friendly, why not take this to then next step and generate POJO interfaces for each entity. These would extend GenericValue but provide a simple gettor/settor facade allowing compile time type checking and removing of the "string" code for much of the business logic written in java.
We have done such a thing (again in our forked application), and it makes the Java code much more readable and easier to use. The general structure is public class Person extends AbstractGenericValue<Person> { public static final String ENTITY = "Person"; // constructor, only called from makeValue, MUST be associated with a delegator protected Person(Delegator delegator) {...} // factory method public static Person newInstance(Delegator delegator) {...} // generate finders, by pkey, etc... public static Person findOne(Delegator delegator, String partyId){...} // getter and settors public String getFirstName() { return getString("firstName"); } public Person setFirstName(String value) { set("firstName", value); return this; } // relationships public Party getParty() throws GenericEntityException {...} public PartyNameView getPartyNameView() throws GenericEntityException{...} } This allows code that is much easier to debug and less error prone.. example below is for navigating orders. OrderHeader orderHeader = OrderHeader.findOne(delegator, orderId); // get the orderItems List<OrderItem> orderItems = orderHeader.getOrderItemList(); BigDecimal totalQuantity = BigDecimal.ZERO; for (OrderItem orderItem: orderItems) { totalQuantity = totalQuantity.add(orderItem.getQuantity()); } I know we want to encourage business logic in minlang, etc... but if it is written in java, and there is a LOT of code in java, shopping cart, etc... this makes that code MUST more readable and maintainable. The binding between the entity model and the java implementation can be caught as a compile time error... significantly lowers the maintenance cost of the code. This may be pushing a rope, but we use this ALL the time for our groovy and java code. (would also apply to jsp code obviously). Minilang code can be type checked by the reader... (want to check for static errors in code, without the need to "run" the code). We have implemented the generators, and the refactoring/abstracting to enable this. We find it works great and doesn't break ANY of the nice ofbiz extend entity semantics, etc.... Of course if you extend an entity and then want java business logic to use it... you need to access those items either with "strings" as stock ofbiz, or redo an entity-gen. But if there is no java code using the entities, no need to auto-gen. As another note, we have done a similar thing with the service interface.... as you might have guessed, we're a fan of ofbiz extensibility, but NOT on how it encourages poor Java implementation practices. ("String" object references, non-type safe, public static methods everywhere.... etc...) Marc ----- Original Message ----- > On 10/12/2010, at 8:54 AM, Adam Heath wrote: > > > On 12/09/2010 01:48 PM, Scott Gray wrote: > >> On 10/12/2010, at 5:53 AM, Adam Heath wrote: > >> > >>> On 12/09/2010 12:03 AM, Scott Gray wrote: > >>>> On 9/12/2010, at 11:50 AM, Adam Heath wrote: > >>>> > >>>>> On 12/08/2010 03:00 PM, Scott Gray wrote: > >>>>>> On 8/12/2010, at 4:29 AM, Adam Heath wrote: > >>>>>> > >>>>>>> I've deprecated findByAnd locally, replacing calls with a > >>>>>>> variant that > >>>>>>> takes a boolean, which specifies whether to use the cache. > >>>>>>> > >>>>>>> Initially, my replacement just added a new findByAnd. However, > >>>>>>> I'm now starting to lean towards replacing with findList > >>>>>>> instead. However, in my opinion, I think that will make > >>>>>>> programming ofbiz more > >>>>>>> difficult. > >>>>>>> > >>>>>>> I'd like to add a findList variant, that takes a Map instead > >>>>>>> of an > >>>>>>> EntityCondition. Without this new variant, there would be ton > >>>>>>> of variants that would only need to import EntityCondition, > >>>>>>> just to > >>>>>>> create a condition. > >>>>>>> > >>>>>>> There are also performance considerations to consider. > >>>>>>> > >>>>>>> EntityCondition.makeCondition(Map) directly takes the map, > >>>>>>> doing no > >>>>>>> processing. However, EntityCondition.makeCondition(Object...) > >>>>>>> eventually calls EntityUtil.makeFields, which does a little > >>>>>>> more than > >>>>>>> UtilMisc. In addition to the iteration over the array, it also > >>>>>>> does a > >>>>>>> check on the value for Comparable/Serializable. This latter > >>>>>>> check seems a bit superfluous, as eventually the base > >>>>>>> condition classes > >>>>>>> check the values against the model. > >>>>>>> > >>>>>>> So, from a purist stand point, even tho findByAnd could be > >>>>>>> replaced by > >>>>>>> findList, I think it is too useful; it saves enough code in > >>>>>>> application layers, imho. > >>>>>>> > >>>>>> > >>>>>> This reminded me of the query objects with method chaining that > >>>>>> I suggested a while back so I threw them together this morning. > >>>>>> > >>>>>> Here are some examples: > >>>>>> thisContent = delegator.findByPrimaryKeyCache("Content", > >>>>>> UtilMisc.toMap("contentId", assocContentId)); > >>>>>> // becomes > >>>>>> thisContent = > >>>>>> EntityOne.query(delegator).from("Content").where("contentId", > >>>>>> assocContentId).cache().find(); > >>>>> > >>>>> api: EntityOne(delegator).from().... > >>>>> > >>>>> in foo.groovy: > >>>>> use(DelegatorCategory) { > >>>>> > >>>>> } > >>>>> > >>>>> class DelegatorCategory { > >>>>> public static EntityOneBuilder EntityOne(Delegator delegator) { > >>>>> return new EntityOneBuilder(delegator); > >>>>> } > >>>>> } class EntityOneBuilder { > >>>>> public EntityOneBuilder from(String entityName) { > >>>>> return this; > >>>>> } > >>>>> > >>>>> public GenericValue query() { > >>>>> return delegator.findOne(....); > >>>>> } > >>>>> } > >>>>> > >>>>> This is almost like what you suggested, but it removes the > >>>>> query() method that starts thte builder, and changes the find() > >>>>> to query(). > >>>>> > >>>>> EntityList would be done the same one. > >>>>> > >>>>> The way you have it, is that the start(EntityOne, EntityList) > >>>>> and the end(find(), list()), are 2 things that have to be > >>>>> remembered. My version just has one thing(the start of the > >>>>> call). > >>>> > >>>> This is all groovy DSL related though right? I hadn't worried > >>>> about groovy too much because I knew we had a fair bit of > >>>> flexibility thanks to the language features. The API I've written > >>>> to date was solely intended for java development but seems > >>>> succinct enough that not much would need to change for groovy. > >>>> > >>>> Also EntityList's execute methods so far are: > >>>> list() iterator() > >>>> first() count() > >>> > >>> All primary methods should be query(), imho. > >>> > >>> interface GenericQueryBuilder<T> { > >>> T query(); > >>> } > >>> > >>> public class EntityOne implements > >>> GenericQueryBuilder<GenericValue> { > >>> public GenericValue query() {} > >>> } > >>> > >>> public class EntityList implements > >>> GenericQueryBuilder<List<GenericValue>>, Iterable<GenericValue> { > >>> public List<GenericValue> query() {} > >>> public Iterator<GenericValue> iterator() {} > >>> ... > >>> } > >> > >> I'm not opposed to that, but I'll need another method name for > >> specifying the delegator. How about use(delegator)? > > > > public final class EntityBuilderUtil { > > public static EntityOne one(Delegator delegator) { > > return new EntityOne(delegator); > > } > > > > public static EntityList list(Delegator delegator) { > > return new EntityList(delegator); > > } > > } > > > > This also means that java api code only needs to import one class. > > Plus, if this class is used as a groovy category, then groovy code > > can do this: > > > > one(delegator).cache(true)..... > > > > As groovy will see one as a method call, taking a variable with type > > Delegator, and search all its categories to find a matching method. > > You'll get all things for free. > > Works for me. > > Thanks > Scott |
|
I have thought about this idea, and at first glance it seems cool and
all, but one of the selling points of OFBiz is that it intentionally stays away from this type of Object->Relational mapping. OFBiz developers find that direct access to the relational database is easier to use. -Adrian On 12/10/2010 7:20 AM, Marc Morin wrote: > In the spirit of changing the entity/delegator interface more object friendly, why not take this to then next step and generate POJO interfaces for each entity. These would extend GenericValue but provide a simple gettor/settor facade allowing compile time type checking and removing of the "string" code for much of the business logic written in java. > > We have done such a thing (again in our forked application), and it makes the Java code much more readable and easier to use. The general structure is > > > public class Person extends AbstractGenericValue<Person> > { > public static final String ENTITY = "Person"; > > // constructor, only called from makeValue, MUST be associated with a delegator > protected Person(Delegator delegator) {...} > > // factory method > public static Person newInstance(Delegator delegator) {...} > > // generate finders, by pkey, etc... > public static Person findOne(Delegator delegator, String partyId){...} > > // getter and settors > public String getFirstName() { > return getString("firstName"); > } > public Person setFirstName(String value) { > set("firstName", value); > return this; > } > > // relationships > public Party getParty() throws GenericEntityException {...} > public PartyNameView getPartyNameView() throws GenericEntityException{...} > } > > This allows code that is much easier to debug and less error prone.. example below is for navigating orders. > > OrderHeader orderHeader = OrderHeader.findOne(delegator, orderId); > > // get the orderItems > List<OrderItem> orderItems = orderHeader.getOrderItemList(); > > BigDecimal totalQuantity = BigDecimal.ZERO; > for (OrderItem orderItem: orderItems) { > > totalQuantity = totalQuantity.add(orderItem.getQuantity()); > } > > I know we want to encourage business logic in minlang, etc... but if it is written in java, and there is a LOT of code in java, shopping cart, etc... this makes that code MUST more readable and maintainable. The binding between the entity model and the java implementation can be caught as a compile time error... significantly lowers the maintenance cost of the code. > > This may be pushing a rope, but we use this ALL the time for our groovy and java code. (would also apply to jsp code obviously). Minilang code can be type checked by the reader... (want to check for static errors in code, without the need to "run" the code). > > We have implemented the generators, and the refactoring/abstracting to enable this. We find it works great and doesn't break ANY of the nice ofbiz extend entity semantics, etc.... Of course if you extend an entity and then want java business logic to use it... you need to access those items either with "strings" as stock ofbiz, or redo an entity-gen. But if there is no java code using the entities, no need to auto-gen. > > As another note, we have done a similar thing with the service interface.... as you might have guessed, we're a fan of ofbiz extensibility, but NOT on how it encourages poor Java implementation practices. ("String" object references, non-type safe, public static methods everywhere.... etc...) > > Marc |
|
This isn't Object->Relational mapping but Relational->Object mapping. It doesn't change ANY of the obiz entity semantics, it just provides a facade over the entities that can optionally be used by Java code (not framework code, but application layer) to recognize that the business logic IS tightly bound to entity (by name), fields (by name) and relationships between entities (by name). THis facade just moves these already existing bindings from "strings" to Java native mechanisms, so that you get compile time errors, if you rename an entity, field, type, relation, etc...
BUT most importantly, you don't get a bunch of GenericValue's and List<GenericValue> in the java application code. They become meaningful business entities that allows code easier to follow and thus less bugs and easier to maintain. Marc Morin Emforium Group Inc. ALL-IN Software 519-772-6824 ext 201 [hidden email] ----- Original Message ----- > I have thought about this idea, and at first glance it seems cool and > all, but one of the selling points of OFBiz is that it intentionally > stays away from this type of Object->Relational mapping. OFBiz > developers find that direct access to the relational database is > easier to use. > > -Adrian > > On 12/10/2010 7:20 AM, Marc Morin wrote: > > In the spirit of changing the entity/delegator interface more object > > friendly, why not take this to then next step and generate POJO > > interfaces for each entity. These would extend GenericValue but > > provide a simple gettor/settor facade allowing compile time type > > checking and removing of the "string" code for much of the business > > logic written in java. > > > > We have done such a thing (again in our forked application), and it > > makes the Java code much more readable and easier to use. The > > general structure is > > > > > > public class Person extends AbstractGenericValue<Person> > > { > > public static final String ENTITY = "Person"; > > > > // constructor, only called from makeValue, MUST be associated > > with a delegator > > protected Person(Delegator delegator) {...} > > > > // factory method > > public static Person newInstance(Delegator delegator) {...} > > > > // generate finders, by pkey, etc... > > public static Person findOne(Delegator delegator, String > > partyId){...} > > > > // getter and settors > > public String getFirstName() { > > return getString("firstName"); > > } public Person setFirstName(String value) { > > set("firstName", value); > > return this; > > } > > > > // relationships > > public Party getParty() throws GenericEntityException {...} > > public PartyNameView getPartyNameView() throws > > GenericEntityException{...} > > } > > > > This allows code that is much easier to debug and less error prone.. > > example below is for navigating orders. > > > > OrderHeader orderHeader = OrderHeader.findOne(delegator, orderId); > > > > // get the orderItems > > List<OrderItem> orderItems = orderHeader.getOrderItemList(); > > > > BigDecimal totalQuantity = BigDecimal.ZERO; > > for (OrderItem orderItem: orderItems) { > > > > totalQuantity = totalQuantity.add(orderItem.getQuantity()); > > } > > > > I know we want to encourage business logic in minlang, etc... but if > > it is written in java, and there is a LOT of code in java, shopping > > cart, etc... this makes that code MUST more readable and > > maintainable. The binding between the entity model and the java > > implementation can be caught as a compile time error... > > significantly lowers the maintenance cost of the code. > > > > This may be pushing a rope, but we use this ALL the time for our > > groovy and java code. (would also apply to jsp code obviously). > > Minilang code can be type checked by the reader... (want to check > > for static errors in code, without the need to "run" the code). > > > > We have implemented the generators, and the refactoring/abstracting > > to enable this. We find it works great and doesn't break ANY of the > > nice ofbiz extend entity semantics, etc.... Of course if you extend > > an entity and then want java business logic to use it... you need to > > access those items either with "strings" as stock ofbiz, or redo an > > entity-gen. But if there is no java code using the entities, no need > > to auto-gen. > > > > As another note, we have done a similar thing with the service > > interface.... as you might have guessed, we're a fan of ofbiz > > extensibility, but NOT on how it encourages poor Java implementation > > practices. ("String" object references, non-type safe, public static > > methods everywhere.... etc...) > > > > Marc |
|
In reply to this post by Marc Morin
make ofbiz more object friendly goes against the orginal design and
David has address why. ========================= BJ Freeman Strategic Power Office with Supplier Automation <http://www.businessesnetwork.com/automation/viewforum.php?f=52> Specialtymarket.com <http://www.specialtymarket.com/> Systems Integrator-- Glad to Assist Chat Y! messenger: bjfr33man Marc Morin sent the following on 12/10/2010 7:20 AM: > In the spirit of changing the entity/delegator interface more object friendly, why not take this to then next step and generate POJO interfaces for each entity. These would extend GenericValue but provide a simple gettor/settor facade allowing compile time type checking and removing of the "string" code for much of the business logic written in java. > > We have done such a thing (again in our forked application), and it makes the Java code much more readable and easier to use. The general structure is > > > public class Person extends AbstractGenericValue<Person> > { > public static final String ENTITY = "Person"; > > // constructor, only called from makeValue, MUST be associated with a delegator > protected Person(Delegator delegator) {...} > > // factory method > public static Person newInstance(Delegator delegator) {...} > > // generate finders, by pkey, etc... > public static Person findOne(Delegator delegator, String partyId){...} > > // getter and settors > public String getFirstName() { > return getString("firstName"); > } > public Person setFirstName(String value) { > set("firstName", value); > return this; > } > > // relationships > public Party getParty() throws GenericEntityException {...} > public PartyNameView getPartyNameView() throws GenericEntityException{...} > } > > This allows code that is much easier to debug and less error prone.. example below is for navigating orders. > > OrderHeader orderHeader = OrderHeader.findOne(delegator, orderId); > > // get the orderItems > List<OrderItem> orderItems = orderHeader.getOrderItemList(); > > BigDecimal totalQuantity = BigDecimal.ZERO; > for (OrderItem orderItem: orderItems) { > > totalQuantity = totalQuantity.add(orderItem.getQuantity()); > } > > I know we want to encourage business logic in minlang, etc... but if it is written in java, and there is a LOT of code in java, shopping cart, etc... this makes that code MUST more readable and maintainable. The binding between the entity model and the java implementation can be caught as a compile time error... significantly lowers the maintenance cost of the code. > > This may be pushing a rope, but we use this ALL the time for our groovy and java code. (would also apply to jsp code obviously). Minilang code can be type checked by the reader... (want to check for static errors in code, without the need to "run" the code). > > We have implemented the generators, and the refactoring/abstracting to enable this. We find it works great and doesn't break ANY of the nice ofbiz extend entity semantics, etc.... Of course if you extend an entity and then want java business logic to use it... you need to access those items either with "strings" as stock ofbiz, or redo an entity-gen. But if there is no java code using the entities, no need to auto-gen. > > As another note, we have done a similar thing with the service interface.... as you might have guessed, we're a fan of ofbiz extensibility, but NOT on how it encourages poor Java implementation practices. ("String" object references, non-type safe, public static methods everywhere.... etc...) > > Marc > ----- Original Message ----- >> On 10/12/2010, at 8:54 AM, Adam Heath wrote: >> >>> On 12/09/2010 01:48 PM, Scott Gray wrote: >>>> On 10/12/2010, at 5:53 AM, Adam Heath wrote: >>>> >>>>> On 12/09/2010 12:03 AM, Scott Gray wrote: >>>>>> On 9/12/2010, at 11:50 AM, Adam Heath wrote: >>>>>> >>>>>>> On 12/08/2010 03:00 PM, Scott Gray wrote: >>>>>>>> On 8/12/2010, at 4:29 AM, Adam Heath wrote: >>>>>>>> >>>>>>>>> I've deprecated findByAnd locally, replacing calls with a >>>>>>>>> variant that >>>>>>>>> takes a boolean, which specifies whether to use the cache. >>>>>>>>> >>>>>>>>> Initially, my replacement just added a new findByAnd. However, >>>>>>>>> I'm now starting to lean towards replacing with findList >>>>>>>>> instead. However, in my opinion, I think that will make >>>>>>>>> programming ofbiz more >>>>>>>>> difficult. >>>>>>>>> >>>>>>>>> I'd like to add a findList variant, that takes a Map instead >>>>>>>>> of an >>>>>>>>> EntityCondition. Without this new variant, there would be ton >>>>>>>>> of variants that would only need to import EntityCondition, >>>>>>>>> just to >>>>>>>>> create a condition. >>>>>>>>> >>>>>>>>> There are also performance considerations to consider. >>>>>>>>> >>>>>>>>> EntityCondition.makeCondition(Map) directly takes the map, >>>>>>>>> doing no >>>>>>>>> processing. However, EntityCondition.makeCondition(Object...) >>>>>>>>> eventually calls EntityUtil.makeFields, which does a little >>>>>>>>> more than >>>>>>>>> UtilMisc. In addition to the iteration over the array, it also >>>>>>>>> does a >>>>>>>>> check on the value for Comparable/Serializable. This latter >>>>>>>>> check seems a bit superfluous, as eventually the base >>>>>>>>> condition classes >>>>>>>>> check the values against the model. >>>>>>>>> >>>>>>>>> So, from a purist stand point, even tho findByAnd could be >>>>>>>>> replaced by >>>>>>>>> findList, I think it is too useful; it saves enough code in >>>>>>>>> application layers, imho. >>>>>>>>> >>>>>>>> >>>>>>>> This reminded me of the query objects with method chaining that >>>>>>>> I suggested a while back so I threw them together this morning. >>>>>>>> >>>>>>>> Here are some examples: >>>>>>>> thisContent = delegator.findByPrimaryKeyCache("Content", >>>>>>>> UtilMisc.toMap("contentId", assocContentId)); >>>>>>>> // becomes >>>>>>>> thisContent = >>>>>>>> EntityOne.query(delegator).from("Content").where("contentId", >>>>>>>> assocContentId).cache().find(); >>>>>>> >>>>>>> api: EntityOne(delegator).from().... >>>>>>> >>>>>>> in foo.groovy: >>>>>>> use(DelegatorCategory) { >>>>>>> >>>>>>> } >>>>>>> >>>>>>> class DelegatorCategory { >>>>>>> public static EntityOneBuilder EntityOne(Delegator delegator) { >>>>>>> return new EntityOneBuilder(delegator); >>>>>>> } >>>>>>> } class EntityOneBuilder { >>>>>>> public EntityOneBuilder from(String entityName) { >>>>>>> return this; >>>>>>> } >>>>>>> >>>>>>> public GenericValue query() { >>>>>>> return delegator.findOne(....); >>>>>>> } >>>>>>> } >>>>>>> >>>>>>> This is almost like what you suggested, but it removes the >>>>>>> query() method that starts thte builder, and changes the find() >>>>>>> to query(). >>>>>>> >>>>>>> EntityList would be done the same one. >>>>>>> >>>>>>> The way you have it, is that the start(EntityOne, EntityList) >>>>>>> and the end(find(), list()), are 2 things that have to be >>>>>>> remembered. My version just has one thing(the start of the >>>>>>> call). >>>>>> >>>>>> This is all groovy DSL related though right? I hadn't worried >>>>>> about groovy too much because I knew we had a fair bit of >>>>>> flexibility thanks to the language features. The API I've written >>>>>> to date was solely intended for java development but seems >>>>>> succinct enough that not much would need to change for groovy. >>>>>> >>>>>> Also EntityList's execute methods so far are: >>>>>> list() iterator() >>>>>> first() count() >>>>> >>>>> All primary methods should be query(), imho. >>>>> >>>>> interface GenericQueryBuilder<T> { >>>>> T query(); >>>>> } >>>>> >>>>> public class EntityOne implements >>>>> GenericQueryBuilder<GenericValue> { >>>>> public GenericValue query() {} >>>>> } >>>>> >>>>> public class EntityList implements >>>>> GenericQueryBuilder<List<GenericValue>>, Iterable<GenericValue> { >>>>> public List<GenericValue> query() {} >>>>> public Iterator<GenericValue> iterator() {} >>>>> ... >>>>> } >>>> >>>> I'm not opposed to that, but I'll need another method name for >>>> specifying the delegator. How about use(delegator)? >>> >>> public final class EntityBuilderUtil { >>> public static EntityOne one(Delegator delegator) { >>> return new EntityOne(delegator); >>> } >>> >>> public static EntityList list(Delegator delegator) { >>> return new EntityList(delegator); >>> } >>> } >>> >>> This also means that java api code only needs to import one class. >>> Plus, if this class is used as a groovy category, then groovy code >>> can do this: >>> >>> one(delegator).cache(true)..... >>> >>> As groovy will see one as a method call, taking a variable with type >>> Delegator, and search all its categories to find a matching method. >>> You'll get all things for free. >> >> Works for me. >> >> Thanks >> Scott > |
|
In reply to this post by Marc Morin
the "facade" is exactly what ofbiz wants to avoid.
the extra overhead of the conversion. Marc Morin sent the following on 12/10/2010 8:17 AM: > This isn't Object->Relational mapping but Relational->Object mapping. It doesn't change ANY of the obiz entity semantics, it just provides a facade over the entities that can optionally be used by Java code (not framework code, but application layer) to recognize that the business logic IS tightly bound to entity (by name), fields (by name) and relationships between entities (by name). THis facade just moves these already existing bindings from "strings" to Java native mechanisms, so that you get compile time errors, if you rename an entity, field, type, relation, etc... > > BUT most importantly, you don't get a bunch of GenericValue's and List<GenericValue> in the java application code. They become meaningful business entities that allows code easier to follow and thus less bugs and easier to maintain. > > > Marc Morin > Emforium Group Inc. > ALL-IN Software > 519-772-6824 ext 201 > [hidden email] > > ----- Original Message ----- >> I have thought about this idea, and at first glance it seems cool and >> all, but one of the selling points of OFBiz is that it intentionally >> stays away from this type of Object->Relational mapping. OFBiz >> developers find that direct access to the relational database is >> easier to use. >> >> -Adrian >> >> On 12/10/2010 7:20 AM, Marc Morin wrote: >>> In the spirit of changing the entity/delegator interface more object >>> friendly, why not take this to then next step and generate POJO >>> interfaces for each entity. These would extend GenericValue but >>> provide a simple gettor/settor facade allowing compile time type >>> checking and removing of the "string" code for much of the business >>> logic written in java. >>> >>> We have done such a thing (again in our forked application), and it >>> makes the Java code much more readable and easier to use. The >>> general structure is >>> >>> >>> public class Person extends AbstractGenericValue<Person> >>> { >>> public static final String ENTITY = "Person"; >>> >>> // constructor, only called from makeValue, MUST be associated >>> with a delegator >>> protected Person(Delegator delegator) {...} >>> >>> // factory method >>> public static Person newInstance(Delegator delegator) {...} >>> >>> // generate finders, by pkey, etc... >>> public static Person findOne(Delegator delegator, String >>> partyId){...} >>> >>> // getter and settors >>> public String getFirstName() { >>> return getString("firstName"); >>> } public Person setFirstName(String value) { >>> set("firstName", value); >>> return this; >>> } >>> >>> // relationships >>> public Party getParty() throws GenericEntityException {...} >>> public PartyNameView getPartyNameView() throws >>> GenericEntityException{...} >>> } >>> >>> This allows code that is much easier to debug and less error prone.. >>> example below is for navigating orders. >>> >>> OrderHeader orderHeader = OrderHeader.findOne(delegator, orderId); >>> >>> // get the orderItems >>> List<OrderItem> orderItems = orderHeader.getOrderItemList(); >>> >>> BigDecimal totalQuantity = BigDecimal.ZERO; >>> for (OrderItem orderItem: orderItems) { >>> >>> totalQuantity = totalQuantity.add(orderItem.getQuantity()); >>> } >>> >>> I know we want to encourage business logic in minlang, etc... but if >>> it is written in java, and there is a LOT of code in java, shopping >>> cart, etc... this makes that code MUST more readable and >>> maintainable. The binding between the entity model and the java >>> implementation can be caught as a compile time error... >>> significantly lowers the maintenance cost of the code. >>> >>> This may be pushing a rope, but we use this ALL the time for our >>> groovy and java code. (would also apply to jsp code obviously). >>> Minilang code can be type checked by the reader... (want to check >>> for static errors in code, without the need to "run" the code). >>> >>> We have implemented the generators, and the refactoring/abstracting >>> to enable this. We find it works great and doesn't break ANY of the >>> nice ofbiz extend entity semantics, etc.... Of course if you extend >>> an entity and then want java business logic to use it... you need to >>> access those items either with "strings" as stock ofbiz, or redo an >>> entity-gen. But if there is no java code using the entities, no need >>> to auto-gen. >>> >>> As another note, we have done a similar thing with the service >>> interface.... as you might have guessed, we're a fan of ofbiz >>> extensibility, but NOT on how it encourages poor Java implementation >>> practices. ("String" object references, non-type safe, public static >>> methods everywhere.... etc...) >>> >>> Marc > |
|
On 12/10/2010 11:54 AM, BJ Freeman wrote:
> the "facade" is exactly what ofbiz wants to avoid. > the extra overhead of the conversion. I disagree. OOTB ofbiz should not use any such facades. But having them available for end-users to make use of is a win, IMHO. Makes it easier for new people to get involved in ofbiz. This facade pattern will obviously be slower; it contains more object instantiations, and more method calls. And, in groovy at least, those end up using reflection. But if it allows people to write more application code, which can later be optimized to be faster, then I'm all for it. |
|
I am happy as long as not OOTB
I doubt that there will be any effort to optimize, under current design, if they are done in OO way. as you said the path of least resistance with the fact that the volunteer group does not have energy to do that. ==================== BJ Freeman Strategic Power Office with Supplier Automation <http://www.businessesnetwork.com/automation/viewforum.php?f=52> Specialtymarket.com <http://www.specialtymarket.com/> Systems Integrator-- Glad to Assist Chat Y! messenger: bjfr33man Adam Heath sent the following on 12/10/2010 10:17 AM: > On 12/10/2010 11:54 AM, BJ Freeman wrote: >> the "facade" is exactly what ofbiz wants to avoid. >> the extra overhead of the conversion. > > I disagree. > > OOTB ofbiz should not use any such facades. But having them available > for end-users to make use of is a win, IMHO. Makes it easier for new > people to get involved in ofbiz. > > This facade pattern will obviously be slower; it contains more object > instantiations, and more method calls. And, in groovy at least, those > end up using reflection. But if it allows people to write more > application code, which can later be optimized to be faster, then I'm > all for it. > |
| Free forum by Nabble | Edit this page |
