Search This Blog

Showing posts with label business model design. Show all posts
Showing posts with label business model design. Show all posts

Friday, May 25, 2018

Web - How to avoid issues with data-bound controls due to missing or non-unique key values

Check out the Web - How to avoid issues with data-bound controls due to missing or non-unique key values KB article to make sure that your business model is aligned with the best practices. Here is a short extract:


Symptoms
You may notice the following side-effects in a Web ListView while it may work fine in WinForms:
- A wrong DetailView may be selected when an unsaved record is clicked in ListView;
- ListView may have no selection column;
- In inline edit or batch mode, all records may become selected or editable.
These effects are especially frequent in a non-persistent class ListView or a nested ListView for an aggregated details collection with newly added or unsaved records.

Explanation
All new records added to the ListView and not yet saved to the database will be assigned with a temporary key value (e.g. -1 or an empty Guid/String value depending on your key type). In a Web application, ListView uses a business class key property to identify records, because there is no way to access real business objects from the web browser. Hence, there is a requirement that each business object must have a unique value assigned to the key property. ASPxGridView and other data-bound controls require this for the correct operation of such features like selection, filtering, sorting, grouping and the standard XAF functionality that depends on them (see also ASPxGridBase > KeyFieldName). 
If a key property is missing in a business class completely or if a key property is not initialized with a unique value immediately after the record is created, these duplicate or invalid records may lead to a data-bound control malfunction as expected.


Please inform me of your health-check results!

FreeImages.Com

Friday, April 20, 2018

XAF v18.1 - An application will not start if there are non-existent member or type info for the Application Model elements

Starting with v18.1, we have introduced checks for type and member info existence at the core level. If a type or member is not existent, the exception will be thrown by default:


NOTE: Type and member info is mandatory as ALL standard and third-party modules rely on it. We do NOT recommend disabling this check in production, because your application will still fail later (you may not notice it and it will happen on an end-user machine).

Typical but not all scenarios where you may see this error are:
- Code changes to an underlying object type structure. For instance, class renaming or removing, namespace or assembly changing; member renaming, removing or its underlying type changing (also applied to custom fields added at runtime).
- Invalid model differences for changed types and members are still present (e.g., for ListView columns and a DetailView layout, appearance and validation rules).

Please refer to this Support Center article for more details on possible solutions and ways to disable this behavior.

Wednesday, September 13, 2017

Simplifying the use of ASPxGridListEditor with XPO classes that have composite keys


Starting with the 17.1.4 version, you can use the built-in StructTypeConverter<T> for composite or compound key properties to enable some built-in DevExpress.Web.ASPxGridView functions in ASPxGridListEditor (e.g., inplace editing and the selection column), which would be missing without a type converter.


This converter can be applied to a struct (Structure in VB.NET) representing your complex key using the standard TypeConverterAttribute:

[TypeConverter(typeof(StructTypeConverter<CompoundKey>))]
public struct CompoundKey { ... }


You can view the full example by the documentation link above.


Despite this minor improvement making the lives of certain XAF users easier (and reducing our support costs too), I must emphasize that we do not recommend using composite keys in new apps. XPO supports such keys for legacy databases only and their use imposes some limitations on the default XAF functionality. You can learn more about this from How to create a persistent object for a database table with a compound key


FreeImages.Com/Kirill Levin

Thursday, September 7, 2017

How to implement the CreatedBy, CreatedOn and UpdatedBy, UpdatedOn properties in a business class

I would like to promote a KB article, which may be interesting for users who are just getting started with our application framework. This information is actually not new and it was already available in the FAQ and Reference sections of our online documentation as well as the support knowledge base.


I must emphasize that there are actually many ways to implement such auditing properties, and your current code may differ from what we show. For instance, one may declare it as "internal  set {...}" or use the PersistentAlias attribute. Just do not be at all concerned. 

You are welcome to share your own implementations in post comments - maybe we can vote for the most concise and beautiful code, eh?:-P


Monday, June 6, 2016

How to access derived (inherited) objects from OData Service

I want to quote a new KB article we created to more easily answer such user questions, especially due to the increased interest in OData in light of the recent arrival of the XAF mobile UI (CTP)

Scenario/Situation
"I created an XPO OData service (XpoDataServiceV3) based on my model, but when I try to query a collection of objects that are derived from another persistent object, the result set includes all objects inherited from the base class. Is it a bug? How can I get only derived objects?"

Explanation/Solution
"This behavior is caused by limited support for derived objects in the OData protocol, which doesn't expose derived classes as entity sets. To access derived objects or their properties, you have to include a type cast using the qualified object type name in the path constructed for a base class. For example, if you wish to get Person objects that are inherited from Party, use the following query:

http://localhost:56789/MyDataService.svc/Party/Person/



Please refer to Derived Entity Type section of the OData Advanced Tutorial and Addressing Derived Types section of the OData protocol documentation for more examples.

Note that this specificity is not related to XPO. If you create a WCF Data Service based on an Entity Framework model, it will behave in a similar manner in regard to derived entities."



And here is a real-life URL query I tested with the data service I created with our MainDemo app and the new Mobile project template:

http://localhost:51562/DataService.svc/DevExpress_Persistent_BaseImpl_Task/MainDemo_Module_BusinessObjects_DemoTask?$filter=Subject%20eq%20%27Task1%27


Again, take special note that this is however, NOT specific to XAF itself or DevExpress ORM OData Service in any way, but rather to the OData V3 protocol itself.


Thursday, March 3, 2016

How to perform CRUD operations with non-persistent objects using standard XAF forms

This post is about our putting a continuous effort into improving XAF developer usability in scenarios requiring manipulation of non-persistent objects or POCOs. Typical scenarios relying on such non-persistent classes include all sorts of confirmation dialogs, user input forms with parameters, lists with temporary data, analysis and reporting data obtained from dynamic runtime calculations, stored procedures (SP), arbitrary SQL queries or third-party services or anything that needs a standard XAF CRUD UI (and, of course, extra modules), but does not require object state to be eventually persisted to the database.

As you probably know, XAF was primarily designed for automatic UI generation tied to one of the two supported persistence layers or ORM technologies - XPO and Entity Framework. Don't get me wrong here: binding standard XAF forms to temporary non-persistent data was always possible (and there are many standard XAF pieces are implemented with it: logon, change the password, about, validation, notification dialogs, etc.), but the number of supported scenarios was quite limited previously. For instance, a year ago there was no really straightforward way of binding a non-persistent list of objects to a ListView directly. It required creating an intermediate non-persistent class holding a collection of non-persistent objects and then showing its DetailView (learn more on this former approach...).

So that is where NonPersistentObjectSpaceProvider, NonPersistentObjectSpace and its ObjectsGetting event first came to the rescue in v15.1 to simplify the lives of XAF developers (learn more...). The current v15.2 brought it to the next level by allowing standard XAF CRUD commands (the New, Delete and Save Actions) for non-persistent objects. The ModifiedObjects property of the NonPersistentObjectSpace class provides access to all created, deleted and modified objects within its scope, unless the IObjectSpace.CommitChangesIObjectSpace.Refresh or IObjectSpace.Rollback methods are called. Step-by-step instructions for implementing this functionality in your XAF v15.2.4+ project are now provided in the online product documentation:

How to: Perform CRUD Operations with Non-Persistent Objects

And here are a couple of screenshots showing what it can look like in the UI*:


Friday, January 15, 2016

How to remove or hide the base class from the New Action's items list

We have recently written a short article describing several methods of accomplishing a popular business model design task, which generated support calls in the past. Some things may already be known to you (e.g., the fact that in XAF you can control many things at the data model class and Controller level), but others are worth repeating, and I hope you will find this article helpful:



As always, I look forward to hearing your feedback in comments to this blog post. Thanks in advance.

Wednesday, December 30, 2015

EF - Use of complex types that are not registered in DbContext and have no key property

I want to highlight a minor usability improvement built into v15.2 for our Entity Framework fans. This is all about a simpler integration of complex types without keys (learn more from EF docs...). 

The situation is already pretty much summarized in the Support Center, and here I just want to re-post the main details. To begin with, consider the following EF classes:

[C#]
public class Product { public Product() { PriceRange = new Range(); } public Int32 ID { get; set; } public String Name { get; set; } public Range PriceRange { get; set; } } public class Range { public Range() { } public Decimal Low { get; set; } public Decimal High { get; set; } }
public class EFDemoDbContext : DbContext {
    ...
    public DbSet<Product> Products { get; set; }
    ...
}

Note that the Range class has no key property and Entity Framework does not map this class to a separate database table. By default, properties of such a class persist in the table mapped to the parent Product class, where the Range type property is declared. So, the Product table will have the ID, NamePriceRange_Low and PriceRange_High columns:

Tuesday, December 22, 2015

MediaDataObject - Declaring images as object references instead of byte array

In v15.2 we have introduced the new MediaDataObject business class. The use of this type mainly reduces traffic in Web apps because images are cached in the browser cache (compared to images declared as byte[]).  

We have invented this solution when optimizing the new Web style performance on mobile devices. 
For instance, in our XCRM demo application (installed to C:\Users\Public\Documents\DevExpress Demos 15.2\Components\eXpressApp Framework\XCRM\, by default) the avatar picture in the top right corner is implemented using MediaDataObject:



Both WinForms and ASP.NET Image Property Editors are used automatically for properties of the MediaDataObject type, the delayed loading is also always enabled - no special attributes are required for this. However, you still can apply the ImageEditorAttribute to customize the editor's options. 

XPO and EntityFramework versions of this type are available in the Business Class LibraryRefer to the eXpressApp Framework > Concepts > Business Model Design > Data Types Supported by built-in Editors > BLOB Image Properties article to see example property declarations for your favorite ORM.

Monday, December 21, 2015

Avoid auto-saving a master when a new non-aggregated child is created and making the New Action available for many-to-many lists

In v15.2.4 we have added the LinkNewObjectToParentImmediately property to the XafApplication and NewObjectViewController classes. 

By default, XafApplication.LinkNewObjectToParentImmediately is set to true to keep the behavior of existing applications unchanged (a new object linked to the master object is created and the master object is committed when the New action is executed in the nested List View). However, in new applications created in the 15.2 version, the default value is overridden to false in code generated by the Solution Wizard.

Use XafApplication.LinkNewObjectToParentImmediately to change the behavior globally (note that this property is hidden in the Application Designer and you can set it only in code). Use NewObjectViewController.LinkNewObjectToParentImmediately to change the behavior for a specific View. The behavior of aggregated collections is not changed.

There are several positive results from this LinkNewObjectToParentImmediately = false change:
1. A reference to the master object is visible in the new child object immediately. 
2. The master object is not committed and the link is not created when the New action is executed in the nested List View. At the database level that means that the reference to the master table is not added to the new child record immediately. The link is created later when the child object is committed. To keep the link, a user should save the master object; otherwise, the unlinked child object will be saved.
3. The New Action is now available directly in the nested ListView or the Link dialog for many-to-many XPO associations!

There were a lot of customer requests for the last two things, so I hope you will like this news. Please let me know what you think in comments.



Monday, December 14, 2015

XPO ORM Data Model Designer and Wizard FAQ

My fellow colleague Michael has recently written an article based on the most popular support calls regarding the visual designer that XPO ships with, for editing visual data models. Some things may already be known to you, but others are worth repeating and I hope you will find this short doc helpful:



How to hide or filter out certain types from the drop-down editor for the System.Type properties

I want to share my recent article on the subject that demonstrates yet another example of how flexible and powerful XAF really is. There, I will describe three possible ways of accomplishing the same task, starting with the most recommended platform-agnostic solution at the business model level (write once, work everywhere) and finishing by manipulating end control properties in the UI for certain platforms and contexts. 


So, let me quite myself from this KB article in our Support Center:

Friday, June 26, 2015

Creating associations between XPO data models in code using the XafTypesInfo API



Prerequisites:
See my About XAF Types Info Subsystem... blog post before reading.

What's New in this regard?
Just wanted to inform you guys that starting with v15.1.4, you can use the solution described in the eXpressApp Framework > Concepts > Business Model Design > Types Info Subsystem > Customize Business Object's Metadata > Create Associations in Code article for that purpose:

The following snippet illustrates how to declare an association between two class' properties when you have no access to these classes code and cannot apply the AssociationAttribute directly.

C#
ITypeInfo typeInfo1 = typesInfo.FindTypeInfo(typeof(DomainObject1));
ITypeInfo typeInfo2 = typesInfo.FindTypeInfo(typeof(DomainObject2));
IMemberInfo memberInfo1 = typeInfo1.FindMember("Object2");
IMemberInfo memberInfo2 = typeInfo2.FindMember("Object1s");
if(memberInfo1 == null) {
    memberInfo1 = typeInfo1.CreateMember("Object2"
        typeof(DomainObject2)
    );
    memberInfo1.AddAttribute(
        new DevExpress.Xpo.AssociationAttribute("A"
        typeof(DomainObject2)), true
    );
}
if(memberInfo2 == null) {
    memberInfo2 = typeInfo2.CreateMember("Object1s"
        typeof(XPCollection<DomainObject1>)
    );
    memberInfo2.AddAttribute(
        new DevExpress.Xpo.AssociationAttribute("A"
        typeof(DomainObject1)), true
    );
    memberInfo2.AddAttribute(
        new DevExpress.Xpo.AggregatedAttribute(), true
    );
}
((XafMemberInfo)memberInfo1).Refresh();
((XafMemberInfo)memberInfo2).Refresh();

Thursday, March 19, 2015

Making sure a property value is unique with XAF and XPO

I wanted to share a link to a hot Support Center discussion on the subject (it has now been unpublished by the author, sorry) with the community members as I believe this business task is not unique:-) and many others should be interested in knowing how to properly handle this.
I am going to detail technical considerations of possible solutions at the application UI and database levels depending on various configurations of your data model including inheritance mapping options (Table per Hierarchy or Table per Type) and soft deletion.

Application UI level

First of all, let's start from the UI part. How would a developer of an XAF app ensure that its end-users are not allowed to save records whose property value or combination of values are unique? 
As you know, XAF ships with a built-in validation module that provides a powerful and extendable validation engine and a large set of predefined attributes to configure common validation rules declaratively. To ensure uniqueness, you can first add the ValidationModule component into your XAF module or application via the designers and then choose from the two built-in rules: RuleCombinationOfPropertiesIsUnique and RuleUniqueValue (it is also possible to turn RuleObjectExists and RuleFromBoolPropert for the same task, but its use is not that straightforward use and I will not talk about it for now). Depending on your preferences, you can either annotate your data model classes with the corresponding code attributes, e.g.:

       [RuleUniqueValue]

       public string Name { ... }


or declare everything at the Application Model level via the Model Editor tool (learn more...). In addition, you can configure the rule's CriteriaEvaluationBehavior parameter, to specify whether to look for modified objects that are currently loaded in memory, in addition to objects in the database itself.
As a result, the XAF's validation engine will consider the rules you configured  when a data record is being saved (technically, when the View.ObjectSpace.Committing event is raised) and will throw ValidationException when uniqueness is violated. This is a special exception type, which is caught by other system controllers to display the validation error in a nice way in the UI:




This would be our topmost  or basic protection level as it handles user input only. It will not help avoid duplicates if the same data records are created in code by a developer who did not call one of the Validator.RuleSet.ValidateXXX methods. 

Thursday, March 12, 2015

How to map ORM data model to another schema, e.g. other than the default "dbo" in MS SQL Server?

I just wanted to bring your attention to the recent update of one of the articles in our support knowledge, which is devoted to advanced data layer customizations - telling XAF business objects to use a different owner schema in the database.



Here we go:

Tuesday, March 3, 2015

Usability improvements for new XAF apps using XPO for data access

I would like to inform you that the next v14.2.6 update of XAF will contain two minor improvements that will help you accomplish two common tasks more easily or help you have less problems with them. Both will affect only new XAF projects created using the Solution Wizard (existing XAF projects will not be touched to avoid collisions). Also, both things were implemented based on the feedback from our users and I hope will be welcomed by them as less work to be done is left for you now.

Here I will shortly outline solution details while you can see the full information by the links below:

T191131: DevExpress.Persistent.BaseImpl - Avoid problems caused by the fact that a new BaseObject record has an empty key value until it is saved

In XAF Solutions created via the Solution Wizard, the BaseObject.OidInitializationMode static property is now set to AfterConstruction using the following code line added to the Module.cs file:
[C#]
BaseObject.OidInitializationMode = OidInitializationMode.AfterConstruction;
We do not modify the default value in the BaseObject class implementation to avoid the behavior change in existing applications.

S173546: Usability - Remove the necessity to manually call the CalculatedPersistentAliasHelper.CustomizeTypesInfo method from custom code when CalculatedPersistentAliasAttribute is used

Now, in XPO-based XAF solutions created with the Solution Wizard the following line is added to the overridden CustomizeTypesInfo method in the Module.cs file:
[C#]
CalculatedPersistentAliasHelper.CustomizeTypesInfo(typesInfo);
You can remove this line if you do not need to use CalculatedPersistentAliasAttribute.

As always, I look forward to your feedback in comments. If you know about other things that may greatly improve your experience as an XAF developer, do not hesitate to let me know.

Simplifying declaration of calculated properties in code for DataView mode with Entity Framework

Starting with v14.2.4 (and even 14.1.9) you can use the DevExpress.ExpressApp.DC.CalculatedAttribute to specify an expression used to calculate a property value of an Entity Framework class in Data View mode:
[C#]
public class Payment { public Int32 ID { get; protected set; } public Decimal Rate { get; set; } public Decimal Hours { { get; set; } [NotMapped, DevExpress.ExpressApp.DC.Calculated("Rate * Hours")] public Decimal CalculatedAmount { get { return Rate * Hours; } }
   // Other data properties and logic...
}
This attribute functions exactly like the DevExpress.Xpo.PersistentAlias attribute applied to a regular business class property. Of course, properties, referenced in the specified expression (using our cross-platform object-oriented criteria language) should be persistent to be able to run an SQL query at the database level. 

To remind you of the DataView mode, this is what you will see in the SQL Server Profiler if you set DataAccessMode = DataView for the Payment_ListView node containing only the Amount column above:

SQL:
SELECT 
    [Limit1].[ID] AS [ID], 
    [Limit1].[C1] AS [C1]
    FROM ( SELECT TOP (2147483647) 
        [Extent1].[ID] AS [ID], 
        [Extent1].[Rate] * [Extent1].[Hours] AS [C1]
        FROM [dbo].[Payments] AS [Extent1]
    )  AS [Limit1]

Note that even though our entity may contain a way more other persistent properties, the query included only the two from the expression above, which increases performance in certain scenarios.
The advantage of this attribute solution is that it is easier to keep your data model logic in one place/class instead of spreading it across multiple layers, e.g., Application Model, where the DataView settings are specified:

XAFML:
<ListView Id="Payment_ListView" DataAccessMode="DataView">
    <Columns>
       <ColumnInfo PropertyName="CalculatedAmount" IsNewNode="True" />
    </Columns>
</ListView>




If you are not sure of which ListView data access mode is best for your particular screen, these guidelines in our docs will help you decide.