Runtime revisions todo list

Posts   
1  /  2  /  3
 
    
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 27-Jun-2004 12:06:36   

Below is the list of actions which will be done in the runtime revisions which will start on monday (yes, I'm at teched next week, but design continues. Implementation will start in the week after that).

At the same time the Access driver will be implemented. With the current driver structure this should not take a lot of time. (2, 3 days tops).

All these actions have top priority. If you don't see an action on the list, but you think it should be included, post a reply. Actions which relate to GUI updates are not implemented in this revision, as this is a runtime library revision simple_smile .

Especially on the predicate front there might be additions possible.

Runtime library * [s](ID: 260) [10] Field values should be able to be set to the result of an expression. Done * (ID: 259) [10] Paging support for collections (SelfServicing and Adapter). Use methods which work on all versions of the database targeted by the DQE (so no 'table' type paging in sqlserverDone * (ID: 257) [10] Adapter: when an identity value is read back and refetch is set to false, the entity is marked out of sync: however reading hte PK value has to be possible.Done * (ID: 250) [10] Ability to tell an entity to ignore values for fields if that value is the sameDone * (ID: 242) [10] All ORMException classes have to derive from a single ORMexception base class, not from ApplicationException.Done * (ID: 237) [10] Add EntityField.IsForeignKeyDone * (ID: 235) [10] Field fetches have to store the original value read from the DB in a special parameterDone * (ID: 234) [10] Support for a UnitOfWork tracking mechanism, which tracks changes instead of executing them and executes these changes when the user calls a special methodDone * (ID: 231) [10] SavePoint support in transactions. Add it to the interface and implement it in the templates, due to lack of .Save() support in IDbTransaction.Done * (ID: 226) [10] Oracle: when schema is empty, do not embed the schema in the SQL.Done. * (ID: 162) [10] Ability to specify which properties to load up front and which properties to load on demand.(Combine with multi fetch)Dropped * (ID: 153) [10] Ability to change PK values.Done. * (ID: 152) [10] Ability to Multi-Fetch sets. (Multi-fetch sets are sets which specify which related objects to fetch in one go. These fetches are always just 1 level deep. So you can specify with a fetch of customer: Fetch orders, Fetch Employees. These are loaded in 2 queries together with the fetch of Customer. You can also do this with fetch customers (multi): specify also that you want to load Orders This will result in 2 queries, instead of n+1 queries.) Done * (ID: 146) [10] Add multi-level versioning to entity field values, and control these with SaveChanges(Name) and RollbackChanges(Name) and ApplyChanges()Done * (ID: 111) [10] Add design time support for collections and entitiesDropped due to crappyness of VS.NET 2002/3 / lack of documentation. * (ID: 96) [10] Adapter: make it possible to supply the entity fetch routine with a datareader filled somewhere else (for example with data originated from a stored procDropped * (ID: 50) [10] Predicates to add: (ID: 267) [10] FieldCompareExpressionDone (ID: 266) [10] FieldCompareSetDone (ID: 265) [10] FieldFullTextSearch (SqlServer specific)Done

  • (ID: 52) [10] Predicates which compare values and the LIKE predicates have to get a parameter which switches off the case sensitivityDone. The solution is specific for the LIKE predicate. Function support will be added in the future which will solve this for all fields.
  • (ID: 270) [10] Enable multi-join of same entity. Add alias specification to Add() routine of RelationCollectionDone.
  • (ID: 271) [10] Enable filtering on fields in multiple joined entitiesDone.
  • (ID: 269) [10] Enable Join with selfDone.
  • (ID: 263) [10] Expression syntaxis for expressions working on fieldsDone
  • (ID: 264) [10] Aggregate functions support and group by implementations with Having clause.Done Core
  • (ID: 238 ) [5] Ability to specify which elements to refresh in a catalog refresh (thus 'exclude stored procs' for example)Done Note: see hotfix released on 10-jul-2004 Templates
  • (ID: 249) [10] TypedView/Typedlists should return default value when value is NULL Done
  • (ID: 163) [10] Transaction support for sp calls in selfservicingDone
  • (ID: 114) [10] When an FK field is set to a new value, a referenced object with that value should be set to null IF the fk value is different.Done

New: - COM+ in Adapter. (Juval Lowy talked about enterprise services on monday, not that I agreed with all of it, but it can be very interesting and the absense of COM+ support in adapter can be a cumbersome thing to work around. Done

Frans Bouma | Lead developer LLBLGen Pro
swallace
User
Posts: 648
Joined: 18-Aug-2003
# Posted on: 28-Jun-2004 20:43:21   

This is an ambitious list. I see all the things I'm after, especially aggregates and paging support. What's your expected timeframe for this?

Answer
User
Posts: 363
Joined: 28-Jun-2004
# Posted on: 28-Jun-2004 21:41:07   

(ID: 118 ) [10] Ability to create an entity with an own set of fields defined. Adapter can't handle this at the moment

confused How come!!?!?!

I just bought the tool, i was looking forward to that feature too..

Here is a couple things i would like to see... Ability to create duplicate entities..let me give you an example,

I have a products table, i want to be able to create two "product entities" one with some extra fields and all relations, and anthor with some relations hidden and no extra fields.

I suppose i could do this now, by only exposing the things i want but that would require me doing more coding stuck_out_tongue_winking_eye

jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 28-Jun-2004 21:42:02   

I don't think I see it up there, but how about the ability to specify a typed list on the fly, including joins and fields from multiple tables and aggregates?

Jeff...

wayne avatar
wayne
User
Posts: 611
Joined: 07-Apr-2004
# Posted on: 28-Jun-2004 23:20:24   

jeffreygg wrote:

I don't think I see it up there, but how about the ability to specify a typed list on the fly

Yep..I could use that.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 28-Jun-2004 23:36:05   

swallace wrote:

This is an ambitious list. I see all the things I'm after, especially aggregates and paging support. What's your expected timeframe for this?

Most of the things are not that time consuming to implement simple_smile The 2 biggest issues are multi-fetch support and subselects in FieldCompareSet. I estimate that beta can start at the end of July.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 28-Jun-2004 23:38:21   

Answer wrote:

(ID: 118 ) [10] Ability to create an entity with an own set of fields defined. Adapter can't handle this at the moment

confused How come!!?!?!

I just bought the tool, i was looking forward to that feature too..

This is the list of features that WILL be implemented simple_smile This is the export from the todo Items marked as top priority. The one you quoted is actually the single feature which I have to look up what it really meant in detail simple_smile

Here is a couple things i would like to see... Ability to create duplicate entities..let me give you an example, I have a products table, i want to be able to create two "product entities" one with some extra fields and all relations, and anthor with some relations hidden and no extra fields. I suppose i could do this now, by only exposing the things i want but that would require me doing more coding stuck_out_tongue_winking_eye

This will come later on in the year. simple_smile Don't worry.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 28-Jun-2004 23:40:13   

jeffreygg wrote:

I don't think I see it up there, but how about the ability to specify a typed list on the fly, including joins and fields from multiple tables and aggregates? Jeff...

You can do that now already but not with a typed datatable for obvious reasons, as you can't create types at runtime without runtime-code generation simple_smile

You can create a Fieldset, relationcollection, a filter and call the same logic as Fill() does in selfservicing or FetchTypedList in adapter simple_smile

With the aggregates you will be able to do that in code as well, as the gui will be updated AFTER the runtimes will have this feature.

Frans Bouma | Lead developer LLBLGen Pro
jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 29-Jun-2004 00:41:38   

Otis wrote:

jeffreygg wrote:

I don't think I see it up there, but how about the ability to specify a typed list on the fly, including joins and fields from multiple tables and aggregates? Jeff...

You can do that now already but not with a typed datatable for obvious reasons, as you can't create types at runtime without runtime-code generation simple_smile

You can create a Fieldset, relationcollection, a filter and call the same logic as Fill() does in selfservicing or FetchTypedList in adapter simple_smile

With the aggregates you will be able to do that in code as well, as the gui will be updated AFTER the runtimes will have this feature.

Right, the only problem is that there is no way to specify the same table to be joined multiple times (which looks like it will be addressed) and I know there was a problem with field aliases in the event that multiple tables in the typed list contained a column with the same name.

I couldn't remember initially what the limitations were at this point, but knew they were enough to keep me from being able to use it. Glad to see all the great changes coming down the pipeline simple_smile

Jeff...

jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 29-Jun-2004 00:48:10   

You know, just curious (I hope this isn't a dumb question), but do you alert when a change you're making is a breaking change? I'm just curious if any of changes in the latest release, or any of the planned changes in the next release will break existing code... Jeff...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 29-Jun-2004 14:51:18   

(live from TechEd Europe, where the wireless lan is good everywhere except in teh wireless work areas smile )

jeffreygg wrote:

Otis wrote:

jeffreygg wrote:

I don't think I see it up there, but how about the ability to specify a typed list on the fly, including joins and fields from multiple tables and aggregates? Jeff...

You can do that now already but not with a typed datatable for obvious reasons, as you can't create types at runtime without runtime-code generation simple_smile

You can create a Fieldset, relationcollection, a filter and call the same logic as Fill() does in selfservicing or FetchTypedList in adapter simple_smile

With the aggregates you will be able to do that in code as well, as the gui will be updated AFTER the runtimes will have this feature.

Right, the only problem is that there is no way to specify the same table to be joined multiple times (which looks like it will be addressed) and I know there was a problem with field aliases in the event that multiple tables in the typed list contained a column with the same name.

THe multi-join is addressed. The alias issue can be solved by using a ResultsetFields instance simple_smile

[quote] I couldn't remember initially what the limitations were at this point, but knew they were enough to keep me from being able to use it. Glad to see all the great changes coming down the pipeline simple_smile [quote] Join with self/multi-join are pretty severe changes in the overall DQE design simple_smile so I postponed that till the next big change. Join with self/multi-join are my top priority. simple_smile

jeffreygg wrote:

You know, just curious (I hope this isn't a dumb question), but do you alert when a change you're making is a breaking change? I'm just curious if any of changes in the latest release, or any of the planned changes in the next release will break existing code... Jeff...

Yes, every change which breaks code will be notified in the migrating your code section in the documentation. However I don't foresee code breaks with this update.

Frans Bouma | Lead developer LLBLGen Pro
takb
User
Posts: 150
Joined: 12-Mar-2004
# Posted on: 30-Jun-2004 04:05:30   

Can you explain a little more about FieldCompareSet?

In another posting you made the comment:

The 2 biggest issues are multi-fetch support and subselects in FieldCompareSet

Does FieldCompareSet implement subqueries?

You've made the comment before:

Subqueries are always rewritable as joins

but some of my team disagree strongly with this statement and they see subquery support as an important feature.

Any comment?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 30-Jun-2004 09:36:16   

takb wrote:

Can you explain a little more about FieldCompareSet?

In another posting you made the comment:

The 2 biggest issues are multi-fetch support and subselects in FieldCompareSet

Does FieldCompareSet implement subqueries?

You've made the comment before:

Subqueries are always rewritable as joins

but some of my team disagree strongly with this statement and they see subquery support as an important feature.

Any comment?

Yes, subqueries are not always rewritable as joins, the one situation which is not rewritable as joins is the one where you base your resultset on the result set of another query which contains the same rows. You can't do that with a join.

FieldCompareSet will give you the oppertunity to define a set of values for a given field (like SELECT CustomerID FROM Orders WHERE EmployeeID > 3) which are then compared with the field: Field (NOT) IN (subquery). NOT EXISTS and EXISTS can be made with this construct as well: a NOT IN resp. IN query.

Subqueries are harder to implement because they need an instance of the DQE without static members as the DQE with the static members called the code creating the predicate simple_smile

I think FieldCompareSet is the best solution, as it does what it say it does, without diving into 'query' objects and other low level nasties.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 19-Jul-2004 18:38:06   

OK, cleaned up the thread a bit (removed slow-chat postings wink )

Beta start is slipped to the first week of August. This because of the time join-with-self/multiple joins of same entities/filters of multiple joined tables etc. took (4 days longer than anticipated).

Also, the final will be released 'when it is done', which means all code is covered by unittests. Today a glitch was reveiled in the adapter code for firebird which was there during the 4 weeks beta period which showed us beta testing is not as reliable as we thought.

All code added for new features/changes made for new features is tested by new unittests, so this should be fairly straight forward.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 28-Jul-2004 15:38:57   

Expression example (adapter, selfservicing will have this too) in a fetch.


/// <summary>
/// Tests simple expressions on a single entity. (orderdetail)
/// </summary>
[Test]
public void ExpressionTestSimple()
{
    DataAccessAdapter adapter = new DataAccessAdapter();
    ResultsetFields fields = new ResultsetFields(6);

    fields.DefineField(OrderDetailsFieldIndex.OrderId, 0, "OrderId");
    fields.DefineField(OrderDetailsFieldIndex.ProductId, 1, "ProductId");
    fields.DefineField(OrderDetailsFieldIndex.UnitPrice, 2, "TotalPrice");  // use unitprice field because it is already of the type we want.
    fields.DefineField(OrderDetailsFieldIndex.UnitPrice, 3, "UnitPrice");
    fields.DefineField(OrderDetailsFieldIndex.Quantity, 4, "Quantity");
    fields.DefineField(OrderDetailsFieldIndex.Discount, 5, "Discount");

    // Expression for total price: ((unitprice * quantity) - ((unitprice * quantity) * discount) )
    IExpression productPriceExpression = new Expression(
        EntityFieldFactory.Create(OrderDetailsFieldIndex.UnitPrice),
        ExOp.Mul,
        EntityFieldFactory.Create(OrderDetailsFieldIndex.Quantity));
    IExpression discountExpression = new Expression(
        productPriceExpression, 
        ExOp.Mul,
        EntityFieldFactory.Create(OrderDetailsFieldIndex.Discount));
    IExpression totalPriceExpression = new Expression(
        productPriceExpression,
        ExOp.Sub,
        discountExpression);
    fields[2].ExpressionToApply = totalPriceExpression;

    try
    {
        DataTable tlist = new DataTable();
        adapter.FetchTypedList(fields, tlist, null, true);

        // test the values.
        for (int i = 0; i < tlist.Rows.Count; i++)
        {
            float productPrice = (float)(((decimal)tlist.Rows[i]["UnitPrice"]) * ((Int16)tlist.Rows[i]["Quantity"]));
            float totalPrice = productPrice - (productPrice * (float)tlist.Rows[i]["Discount"]);

            Assert.AreEqual( Math.Round(Convert.ToDecimal(tlist.Rows[i]["TotalPrice"]), 3), Math.Round(Convert.ToDecimal(totalPrice), 3) );
        }
    }
    finally
    {
        adapter.Dispose();
    }
}

Note the datatable mumbo jumbo crapcode to produce the same values smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 28-Jul-2004 15:52:02   

With an aggregate and order by to calculate the total of the complete order:


/// <summary>
/// Tests simple expressions on a single entity (orderdetail), using a groupby on orderID and
///  calculates the total price of the complete order.
/// </summary>
[Test]
public void ExpressionTestSimpleGroupByAggregate()
{
    DataAccessAdapter adapter = new DataAccessAdapter();
    ResultsetFields fields = new ResultsetFields(2);

    fields.DefineField(OrderDetailsFieldIndex.OrderId, 0, "OrderId");
    fields.DefineField(OrderDetailsFieldIndex.UnitPrice, 1, "TotalPrice");  // use unitprice field because it is already of the type we want.

    // Expression for total price: ((unitprice * quantity) - ((unitprice * quantity) * discount) )
    IExpression productPriceExpression = new Expression(
        EntityFieldFactory.Create(OrderDetailsFieldIndex.UnitPrice),
        ExOp.Mul,
        EntityFieldFactory.Create(OrderDetailsFieldIndex.Quantity));
    IExpression discountExpression = new Expression(
        productPriceExpression, 
        ExOp.Mul,
        EntityFieldFactory.Create(OrderDetailsFieldIndex.Discount));
    IExpression totalPriceExpression = new Expression(
        productPriceExpression,
        ExOp.Sub,
        discountExpression);
    fields[1].ExpressionToApply = totalPriceExpression;
    fields[1].AggregateFunctionToApply = AggregateFunction.Sum;
    IGroupByCollection groupByClause = new GroupByCollection();
    groupByClause.Add(fields[0]);

    try
    {
        DataTable tlist = new DataTable();
        adapter.FetchTypedList(fields, tlist, null, 0, null, true, groupByClause);
        // view results in grid
        ResultsetViewer viewer = new ResultsetViewer();
        viewer.BindDataTable(tlist);
        viewer.ShowDialog(null);
    }
    finally
    {
        adapter.Dispose();
    }
}

Note that you can re-use the expression objects. You can also create them up front and re-apply them when necessary.

Expressions can be used in update statements (to set fields to a certain value calculated by an expression) or in selects (as you see above, or when you simply specify an expression with an entity field in an entity, that entity field's value will be calculated with the expression.).

Expressions can also be used in a new predicate: FieldCompareExpression. This predicate can be used to create simple field compare field predicates, but also complex predicates.

Expression operators: +, -, /, *, % (modulo, only on SqlServer), AND, OR, & (bitwise and, only on sqlserver), | (bitwise OR, only on sqlserver), ^ (bitwise xor, only on sqlserver) Expression possibilities: Field Field ExOp Field Field ExOp Value Field ExOp Expression Value ExOp Field Expression ExOp Field Expression ExOp Expression

You probably miss a couple of combinations, this is due to the fact that the 'value' can have any type, but the value is stored in a parameter, and the type of that parameter is determined from the field which is the other operand.

Frans Bouma | Lead developer LLBLGen Pro
jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 28-Jul-2004 23:40:04   

How about instead of:

Otis wrote:


    IExpression productPriceExpression = new Expression(
        EntityFieldFactory.Create(OrderDetailsFieldIndex.UnitPrice),
        ExOp.Mul,
        EntityFieldFactory.Create(OrderDetailsFieldIndex.Quantity));

You do this:


    IExpression productPriceExpression = new Expression(
        fields[0], //Price
        ExOp.Mul,
        fields[1]; //Quantity

Let use use already defined fields in the ResultSetFields collection to perform calculations on. This will allow us to use expressions against specific fields from specific relationships. This will let me create the following expression:



    DataAccessAdapter adapter = new DataAccessAdapter();
    ResultsetFields fields = new ResultsetFields(2);

    fields.DefineField(LocationFieldIndex.MileageMarker, 0, "BeginLocation");
    fields.DefineField(LocationFieldIndex.MileageMarker, 1, "EndLocation"); 

    // Distance between locations = EndLocationMileageMarker - BeginLocationMileageMarker
    IExpression mileageExpression = new Expression(
        fields[0],
        ExOp.Sub,
        fields[1])

Or perhaps not "instead of", but "in addition to" as an overload. Without this kind of overload I will not be able to specificy which relationship I want to use for which field.


For the current method, it would better if we can eliminate the EntityFieldFactory.Create method and just specify the FieldIndex to clean up code and reduce typing. In fact, if the .Create method is required, won't this run into problems with serialization? If a concrete instance is serialized and, let's say, the column name changes, won't that result in a bad query when the ResultsetFields collection is deserialized and executed? Seems that it would be better to just specify and store the enum and let the query generater create the field instance at the time of execution... confused


I think it would be good to have an overload for the Fields.DefineField as such:


Fields.DefineField(gettype(integer), 0, "MyField")

Instead of requiring the user to choose an existing field with the appropriate type. What if there is no field available with the appropriate type?


Hmmm....when specifying ResultSetFields how does one specify the relationship to use for the entity the field belongs to...maybe there's an overload?


Also, for operations that are hmmmm....can't remember the term....basically operations that don't matter how many are in them or in which order they are like (a * b * c) or (a + b + c) or (a - b - c) it would be nice to have a specific Expression type like MultiplyExpression that would allow you to specify unlimited numbers to be operated on. OK, so that wasn't the clearest idea in the world. Witness:

In VB you damn C# snobs wink


Dim fields as new ResultSetFields(2)
fields.DefineField(TableFieldIndex.Blah,0,"Blah")
fields.DefineField(TableFieldIndex.Blah2,1,"Blah2")
Dim myExpression as new MultiplyExpression(fields)

This will prevent having to define a new expression object for each pair of numbers you want to operate on. That could get messy with larger/more complex formulas. I wouldn't remove the current Expression type as being able to quickly add two numbers works well for that method, just extend the base expression to accomodate specific operations that need the multi-value support.


I assume it's on the developer to ensure that the Group By clause doesn't result in invalid SQL? i.e., failing to aggregate non-grouped fields, etc?


Looks great! I think it's definitely usable as it stands, except for the ability to specify which specific fields (i.e., which specific entity/relation/field combination) the expressions should operate on. Looking forward to getting my hands on some code!

Jeff...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 29-Jul-2004 10:40:19   

jeffreygg wrote:

How about instead of:

Otis wrote:


    IExpression productPriceExpression = new Expression(
        EntityFieldFactory.Create(OrderDetailsFieldIndex.UnitPrice),
        ExOp.Mul,
        EntityFieldFactory.Create(OrderDetailsFieldIndex.Quantity));

You do this:


    IExpression productPriceExpression = new Expression(
        fields[0], //Price
        ExOp.Mul,
        fields[1]; //Quantity

You can do that too, it accepts any object implementing IEntityFieldCore, which are new fields or existing fields. I illustrated it with new fields, but you can use existing fields as well. For re-usability of expression objects, I think it's best to use new fields though. All that is used of the field objects is hte persistence info and object aliases (when you use a join with self/multiple times the same table)

Let use use already defined fields in the ResultSetFields collection to perform calculations on. This will allow us to use expressions against specific fields from specific relationships. This will let me create the following expression:


    DataAccessAdapter adapter = new DataAccessAdapter();
    ResultsetFields fields = new ResultsetFields(2);

    fields.DefineField(LocationFieldIndex.MileageMarker, 0, "BeginLocation");
    fields.DefineField(LocationFieldIndex.MileageMarker, 1, "EndLocation"); 

    // Distance between locations = EndLocationMileageMarker - BeginLocationMileageMarker
    IExpression mileageExpression = new Expression(
        fields[0],
        ExOp.Sub,
        fields[1])

Or perhaps not "instead of", but "in addition to" as an overload. Without this kind of overload I will not be able to specificy which relationship I want to use for which field.

You can do that. You can specify with the field an ObjectAlias, which is the alias you for example have specified for a given table joined in the relation set. (for example 2 times employee, and you alias the second to 'Manager', you can specify 'Manager' as objectalias for the field, which field to pick)

For the current method, it would better if we can eliminate the EntityFieldFactory.Create method and just specify the FieldIndex to clean up code and reduce typing. In fact, if the .Create method is required, won't this run into problems with serialization? If a concrete instance is serialized and, let's say, the column name changes, won't that result in a bad query when the ResultsetFields collection is deserialized and executed? Seems that it would be better to just specify and store the enum and let the query generater create the field instance at the time of execution... confused

The enum is defined per entity. So CustomerFieldIndex.CustomerID is 0, but OrderFieldIndex.OrderID is also 0. I can only make this work with field indexes if I generate for each entity all constructors. This is definitely not what you want, as it will blow up your project beyond believe if you have a lot of entities.

For now the expressions have to be coded, but in the scheduled gui updates to support these new features, a designer will be added which lets you generate these expressions right into the typed list.

Serialization is not a problem with this.

I think it would be good to have an overload for the Fields.DefineField as such:


Fields.DefineField(gettype(integer), 0, "MyField")

Instead of requiring the user to choose an existing field with the appropriate type. What if there is no field available with the appropriate type?

Good point! A user can of course create a new instance of EntityField or EntityField2 and set some properties (or call one of the constructors). However it's perhaps wise to add an ExpressionField, which contains just an expression and implements IEntityFieldCore. Will do that. Thanks Jeff! simple_smile

Hmmm....when specifying ResultSetFields how does one specify the relationship to use for the entity the field belongs to...maybe there's an overload?

You can specify the alias indeed in an overload, see the example in another thread where I posted a codesnippet.

Also, for operations that are hmmmm....can't remember the term....basically operations that don't matter how many are in them or in which order they are like (a * b * c) or (a + b + c) or (a - b - c) it would be nice to have a specific Expression type like MultiplyExpression that would allow you to specify unlimited numbers to be operated on. OK, so that wasn't the clearest idea in the world. Witness:

In VB you damn C# snobs wink


Dim fields as new ResultSetFields(2)
fields.DefineField(TableFieldIndex.Blah,0,"Blah")
fields.DefineField(TableFieldIndex.Blah2,1,"Blah2")
Dim myExpression as new MultiplyExpression(fields)

This will prevent having to define a new expression object for each pair of numbers you want to operate on. That could get messy with larger/more complex formulas. I wouldn't remove the current Expression type as being able to quickly add two numbers works well for that method, just extend the base expression to accomodate specific operations that need the multi-value support.

I initially had this idea, but doesn't work. THe problem is with the values. Say I want to add this: a * 3 * b easy enough, right? simple_smile Well, because it has to be a flexible constructor, you need to have a variable parameter constructor, which accepts objects. However you then get 3 objects: a, 3 and b. Then, for each object the type has to be determined via reflection. This can get messy and it even is ambiguistic, because what if I want to do this: a + b - 2 the '-' is an enum operator. 2 is a value, both integers. which is a value and which is the enum? You can define for each operator a multi expression like your example, but I don't think that's used very much.

Now the constructor, through polymorphism, knows exactly what the type of which operand is. I also could have used the way predicates are added, but that would be even more verbose.

The other possibility was a string parser, which I really like to avoid because it is slow and error prone to the user.

I assume it's on the developer to ensure that the Group By clause doesn't result in invalid SQL? i.e., failing to aggregate non-grouped fields, etc?

Yes. I moved away from the 'check everything' mantra a bit. These features are advanced stuff and as with everything advanced: know what you're doing or you'll burn your hands (or worse wink ). It's not that hard really, once you've used it a couple of times.

Looks great! I think it's definitely usable as it stands, except for the ability to specify which specific fields (i.e., which specific entity/relation/field combination) the expressions should operate on. Looking forward to getting my hands on some code!

Which fields you're referring to is possible simple_smile

I also added the HAVING clause to the groupby collection, so it gets really advanced now simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 29-Jul-2004 15:56:19   

Btw, that Expressionfield idea isn't required. You can just do: new EntityField() and be done with it, as it will be replaced by the expression anyway and the alias is set by the DefineField() call.

Frans Bouma | Lead developer LLBLGen Pro
jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 29-Jul-2004 20:01:32   

Otis wrote:

Btw, that Expressionfield idea isn't required. You can just do: new EntityField() and be done with it, as it will be replaced by the expression anyway and the alias is set by the DefineField() call.

Thanks for the follow up. Couple of questions.

  1. Is the .DefineField call required, or can you define a resultsetfield apart from that call? Or maybe .DefineField is a function?

  2. In regard to the above (not needing an "ExpressionField"), how then will the type be specified? Perhaps also it might add to readability to have an ExpressionField type.

  3. In regard to the multiple value expressions: How about something like this syntax:


Dim myExpression as New MultiplyExpression
With myExpression
  .AddOperand(x)
  .AddOperand(myOtherExpression)
  .AddOperand(5)
End With

I'm not sure how useful it is to have the ability to add multiple values to a single operator expression, but if anyone needs it having this kind of syntax would be welcome. Of course, you C# bastards are SOL without a "WITH" clause (haha).

Jeff...

<Edit> FYI, I proposed the above syntax to solve the need to manage the types the user wants to add to the expression. If the above syntax is used, then the user won't have to first create a collection, and the framework won't have to figure out which types the user is providing. The .AddOperand methods can have typed overloads...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 29-Jul-2004 21:14:07   

jeffreygg wrote:

Otis wrote:

Btw, that Expressionfield idea isn't required. You can just do: new EntityField() and be done with it, as it will be replaced by the expression anyway and the alias is set by the DefineField() call.

Thanks for the follow up. Couple of questions.

  1. Is the .DefineField call required, or can you define a resultsetfield apart from that call? Or maybe .DefineField is a function?

The typed list fetch logic works with an EntityFields collection. You can easily define that entityfields collection using the Resultsetfields class (which is a subclass of EntityFields and used by every typed list simple_smile ) and it has some additional extra's like it can define aliasses for fields easily.

remember, when the designer supports the design of these columns you won't be coding these by hand simple_smile

  1. In regard to the above (not needing an "ExpressionField"), how then will the type be specified? Perhaps also it might add to readability to have an ExpressionField type.

This is not needed, as the code fills a datatable and the data returned defines the type of the column. The typed property of a typedlist row is generated. simple_smile

  1. In regard to the multiple value expressions: How about something like this syntax:

Dim myExpression as New MultiplyExpression
With myExpression
  .AddOperand(x)
  .AddOperand(myOtherExpression)
  .AddOperand(5)
End With

I'm not sure how useful it is to have the ability to add multiple values to a single operator expression, but if anyone needs it having this kind of syntax would be welcome. Of course, you C# bastards are SOL without a "WITH" clause (haha).

haha simple_smile ) Well I could define a nice operator to make this really easy of course for C# developers smile stuck_out_tongue_winking_eye . In fact: the reason why I don't use the syntax like FastObjects uses (brilliant syntax but it only works in C# due to the operator overloading) is because VB.NET doesn't support operator overloading simple_smile

It's an option, the thing is that you only do multiplications with that expression which can be a little limiting. But no worries, the mechanism is flexible enough so these expressions might be added in the future. simple_smile

Btw, as a nice side effect because HAVING is also implemented, things like: SELECT * FROM table WHERE (field*value) < value and other nice expression filters are also possible now simple_smile

Frans Bouma | Lead developer LLBLGen Pro
jeffreygg
User
Posts: 805
Joined: 26-Oct-2003
# Posted on: 29-Jul-2004 22:03:48   

Otis wrote:

haha simple_smile ) Well I could define a nice operator to make this really easy of course for C# developers smile stuck_out_tongue_winking_eye . In fact: the reason why I don't use the syntax like FastObjects uses (brilliant syntax but it only works in C# due to the operator overloading) is because VB.NET doesn't support operator overloading simple_smile

It's an option, the thing is that you only do multiplications with that expression which can be a little limiting. But no worries, the mechanism is flexible enough so these expressions might be added in the future. simple_smile

Btw, as a nice side effect because HAVING is also implemented, things like: SELECT * FROM table WHERE (field*value) < value and other nice expression filters are also possible now simple_smile

Not familiar with FastObjects (checked out their web site and saw "OQL". Gonna have to check that out). Anyway, my prime concern is make the syntax as fast as possible so how about this: Basically, allow the user to construct the filter "in-line"


Dim myExpression as New Expression 'Generic expression

With myExpression
  .Add(5) 'Could be .Add(ExOp.Add, 5) behind the scenes
  .Add(ExOp.Mult, b) 'Typed overload accepting an int
  .Add(Exop.Sub, myOtherExpression) 'Provides for nesting support
  .Add(Exop.Div, 6)
End With

Basically, construct the expression according to basic rules of precedence and allow the user to manually dictate precendence by adding sub-expressions to designate parenthetical groups.

The whole ideas is to reduce verbosity (how's that for a word?). If it's necessary to construct individual expressions for each operand pair, then do it behind the scenes for us - allow us to create them ourselves if we wish (especially for OO reusability) but allow us to have something that's as lightweight as possible to code against.

Jeff...

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 30-Jul-2004 09:58:31   

jeffreygg wrote:

Otis wrote:

haha simple_smile ) Well I could define a nice operator to make this really easy of course for C# developers smile stuck_out_tongue_winking_eye . In fact: the reason why I don't use the syntax like FastObjects uses (brilliant syntax but it only works in C# due to the operator overloading) is because VB.NET doesn't support operator overloading simple_smile

Not familiar with FastObjects (checked out their web site and saw "OQL". Gonna have to check that out). Anyway, my prime concern is make the syntax as fast as possible so how about this: Basically, allow the user to construct the filter "in-line"


Dim myExpression as New Expression 'Generic expression

With myExpression
  .Add(5) 'Could be .Add(ExOp.Add, 5) behind the scenes
  .Add(ExOp.Mult, b) 'Typed overload accepting an int
  .Add(Exop.Sub, myOtherExpression) 'Provides for nesting support
  .Add(Exop.Div, 6)
End With

Basically, construct the expression according to basic rules of precedence and allow the user to manually dictate precendence by adding sub-expressions to designate parenthetical groups.

The whole ideas is to reduce verbosity (how's that for a word?). If it's necessary to construct individual expressions for each operand pair, then do it behind the scenes for us - allow us to create them ourselves if we wish (especially for OO reusability) but allow us to have something that's as lightweight as possible to code against.

Ok, your second proposal looks interesting. It will take some refactoring but I think I can add this instead of what I have now. Thanks!

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39776
Joined: 17-Aug-2003
# Posted on: 30-Jul-2004 16:55:04   

When implementing this I ran into the same issue I had with my current implementation as well: what to do with values?

As an expression is located in generic code, how to generate parameters for values? I can of course determine type objects for a value (or create 50+ overloads of all the value Add methods wink ) but that doesn't help me much for the parameters. I then have to create conversion tables in the creator objects which accept the .NET type, precision and scale and create the correct dbTyped parameter.

The idea is nice, I'll keep it around, however I'll keep the current implementation for now and change it eventually in de beta period. (as we're already behind schedule)

Frans Bouma | Lead developer LLBLGen Pro
BlueCell avatar
BlueCell
User
Posts: 83
Joined: 12-Jul-2004
# Posted on: 03-Aug-2004 11:33:39   

Any news on the access driver?

1  /  2  /  3