Migrating your code
Preface
With every release of the runtime libraries, designer and accompanying template sets new features are added and changes are made to fix bugs or design flaws.
While we do everything we can to avoid breakage of your code, some changes are unavoidable. This section
illustrates some important points to consider when you move your own code using the LLBLGen Pro generated code to the v3.0 templates and
updated runtime libraries (version number: 3.0.0.0).
Before you proceed, please read the following important notice:
Important: |
Please make backup copies of your work before migrating to v3.0. That is: make backups of your own code and the
generated code before using LLBLGen Pro v3.0. This way you can roll back to your original work and continue working with
2.6 or
earlier versions if you decide that migration to v3.0 requires more work than you anticipated and you have to complete it at a later date. |
Important: |
If you're generating new v3.0 code on top of a project generated with v2.6 or
earlier, it can be that when you load the project(s) into VS.NET, the references to the runtime libraries are still pointing to the v2.6 runtime libraries or
earlier versions. Please make sure you manually update these references to the v3.0 runtime libraries, and if applicable, add the reference to the LinqSupportClasses. See for more details about referencing the runtime libraries the section Compiling your code. |
Furthermore, it's key to regenerate the code and also to check if you're indeed referencing the proper runtime libraries.
Below are the list of breaking changes in every 2.x version as well as the
current version, v3.0. If you're migrating from 1.0.200x.y to v3.0, be sure you read all the breaking changes on this page. If you're migrating from v2.0 to v3.0, you need to check the breaking changes in
v2.0, v2.5 and v2.6 sections. If you're migrating from v2.5, you've to check the
v2.5 and v2.6 section. If you're migrating from v2.6, you only have to check
the v3.0 section. If you run into a breaking change which isn't enlisted here, please let us know so we can add it here.
Migrating generated code from version v2.6 to v3.0 runtime libraries
The following changes are breaking changes introduced by v3.0. Please
check them with your own project to make the transition as smoothly as
possible.
Breaking changes v3.0
Templates
- .NET 1.x / VS.NET 2002/2003 are no longer supported.
- Compact Framework is no longer supported.
- Sub-types now always inherit their PK fields from their super-type,
their own PK fields always have the same names.
- Fields have no index anymore. This leads to a problem in which order
PK fields and UC fields are emitted into the method signatures. The
fields are ordered by their name, ascending. This could lead to a
breaking change when migrating v2.x code to v3.x when a compound PK or
UC with two or more fields with the same type are used. You have to
examine calls to the fetch methods using PK and UC directives as well as
CTor calls to entities with a PK of 2 or more fields.
- Oracle, ODP.NET: Calling a retrieval stored procedure
with one or more cursors will give default datatable names, instead of
the names of the cursor parameters. This is necessary because there's no
notion of what an OracleCursor object is as there's no reference to
ODP.NET
- Stored procedure call code no longer has overloads which
accept/return ReturnValue values.
- If an output parameter of a stored procedure is NULL, in previous
versions the method member was left untouched. In v3, the member is set
to null if the member is of type Nullable<T> and the default value for
the type if the member is of another type. Default value is calculated
with the FieldUtilities class: string has as default value string.Empty,
guid: empty guid and byte[]: empty array.
- VB.NET, 2010 specific: Starting with VS.NET 2010, the build
output folders are bin\debug and bin\release, instead of just bin, which
is equal to the pattern VS.NET uses.
- SelfServicing: DbUtils has been removed. The static settings
and methods are moved to the DaoBase class. The Db specific methods for
sqlserver, like SetArithAbortFlag and SetSqlserverCompatibilityLevel are
moved to the new class
CommonDaoBase, which is located in the DaoClasses namespace. As
DbUtils' public properties are not used frequently in an application,
breaking code is minimal: rename the call / reference to the DbUtils
member to a call to the CommonDaoBase class method / property instead.
The DbUtils.CreateTransaction(3) method has been removed (there's no
replacement in CommonDaoBase). The reason is that 'name' is no longer
used. Use the overload which don't accept a name. This method also has
been moved to DaoBase / IDao and is now no longer static. It's not
likely you use this method in practice.
- Adapter: DataAccessAdapter is now generated using a shared
template. This means that a lot of code has been moved to the base
class.One of the methods which is moved is the InsertPersistenceLogic
for predicates. This method contained a user code region in the default
(case else) clause. If you had code added to that region, please
override OnInsertPersistenceObjects() in a partial class of
DataAccessAdapter and add your code to that method instead.
- The connection string key name has changed. Please check the
generated app.config file in the DbSpecific project (adapter) or the
generated code project (selfservicing) for details on the connection
string key name and copy it over to your application's app/web.config
file.
Runtime Libraries
- Oracle ODP.NET: There's now just 1 DQE for ODP.NET, instead
of 1. If using Oracle 8i, you have to switch off Ansi Joins using the
Application Configuration file settings as Ansi joins are now
enabled by default.
- SQL Server: The default compatibility level is now set to SQL
Server 2005. If you're using SQL Server 2000, you have to set the
compatibility level to 1 through the
Application Configuration file settings. Code targeting SQL Server
2000 which is generated using the default compatibility level will
likely crash due to exceptions as the SQL can be incompatible (TOP
clauses using parameters, CTE based paging etc.)
- Firebird. The FirebirdCompatibilityLevel enum is now located
in the ORMSupportClasses assembly.
- Some methods have been removed or made private. In general this
shouldn't be a problem as they weren't meant for usage outside the
framework itself. If you use a method like GetFieldByName, use the
string indexer on the Fields object in the entity instead.
Migrating generated code from version v2.5 to v2.6 runtime libraries
A lot of the breaking changes are made on the .NET 2.0+ code only. This is due to the fact that the .NET 1.x codebase has reached its end of life (as well as the
CF.NET 1.x code). LLBLGen Pro v2.6 does ship with .NET 1.x code support, but not a lot of the changes in v2.6 are made to that codebase as well. You're encouraged to upgrade to at least .NET 2.0.
Breaking changes v2.6
Runtime libraries
- Due to heavy refactoring, some of the protected methods of DaoBase and DataAccessAdapter which were used internally for for example prefetch path execution have been moved to another class, PersistenceCore and made internal static. If your code relies on these methods, please rewrite your code so they don't rely on these methods anymore. This and other refactorings were performed to remove clones inside the codebase and to make the code more maintainable.
- RelationCollection and IRelationCollection’s indexer now returns an
IRelation instead of IEntityRelation. This indexer (Item in VB.NET) returns either an IEntityRelation or an IDynamicRelation object, which derive from IRelation
- SelfServicing: in prefetch paths, the intermediate entity in m:n relations is now aliased with the same pattern as the GetMultiManyToManyField method uses: Entityname_. Example: "Order_". Previously this was an empty string. Adapter already uses this pattern.
- .NET 2.0+: IEntityFactory(2).CreateHierarchyRelations() isn't virtual anymore. Instead, override the new IEntityFactory(2).CreateHierarchyRelations(string) method.
- .NET 2.0+: IEntityFactory2.GetEntityTypeFilter(bool) isn't virtual anymore. Instead, override the new IEntityFactory2.GetEntityTypeFilter(bool, string).
- DbFunctionCall now doesn't ignore schema or catalog names specified anymore when the function name is a pre-formatted string. This doesn't normally lead to breaking code as the names were ignored previously, but just in case you passed the names, they're now having effect.
- IProjection has new members, which you have to implement in your code if you implemented IProjection previously.
- IPredicate now has 2 new interface members: GetFrameworkElementsInPredicate() (method) and ObjectAlias (property). Custom predicate implementation have to make sure these members return the correct values with respect to the custom predicate. ObjectAlias is now implemented on Predicate, the abstract base class of all predicates. If your custom predicate inherits from this class, you can remove the ObjectAlias property from your predicate. GetFrameworkElementsInPredicate returns a list of objects, which are all LLBLGen Pro framework elements, so entity fields, expression objects and the like, contained inside the predicate.
- .NET 2.0+: IEntityField.ToXml has been removed.
- .NET 2.0+: EntityField and EntityField2 have been refactored to use a shared base class, EntityFieldCore. This could lead to deserialization problems if you deserialize binary serialized predicates back which are serialized using older runtime versions
- .NET 2.0+: EntityField/EntityField2 now consume less memory (-20%) as elements which aren’t used with entities are factored into separate classes/objects. This brings down memory consumption in fields, though could lead to errors during deserialization if you deserialize binary serialized predicates back which are serialized using older runtime versions
- .NET 2.0+, SqlServer, CE: On .NET 2.0+, SqlServer CE 3.0 or higher is supported, as the DQE uses named parameters in the queries. If you're using an older version of SqlServer CE, you've to upgrade to that newer version, recommended is v3.5 or higher.
- .NET 2.0+, SqlServer, CE Desktop: LLBLGen Pro now uses the normal SqlServer DQE for generating queries for SqlServer CE Desktop, so migrating an existing CE Desktop targeting VS.NET project to v2.6 requires that you change the references to the SqlServer DQE. You also have to set the SqlServerCompatibilityLevel in your application's .config file to 3 for SqlServerCE 3.x and 4 for SqlServerCE 3.5
- If you’re using your own VS.NET templates, the <[RuntimeLibraryHintPath]> token is no longer used. You’ve to append the .NET version number, e.g.: <[RuntimeLibraryHintPath20]> for .NET 2.0 runtime libraries.
- If you add the same entity object twice to a collection, which is contained inside an entity, e.g. you add myOrder twice to myCustomer.Orders, it is now added twice and not as before, added once. If you set the property DoNotPerformAddIfPresent to true on the collection, the entity is added once. DoNotPerformAddIfPresent is false by default. This change is caused by the fact that if you set a property mapped onto a relation to the same object (e.g. myOrder.Customer = myCustomer; where myOrder.Customer was already set to myCustomer), it’s no longer desynced and re-synced, the set is a simple no-op, as nothing has to be done. This means that if you add myOrder twice to myCustomer.Orders, it’s no longer first desynced from myCustomer, and therefore it’s not removed from the collection before it’s added. Normally this isn’t a problem, only when you tend to add entities multiple times to a collection, have DoNotPerformAddIfPresent set to false and rely on the # of entities in the collection. To work around this: either set the flag DoNotPerformAddIfPresent to true or prevent adding the same entity twice, if you really have to rely on the # of unique entities in a collection.
- .NET 2.0+: When CancelEdit() is called (either by manual code or by a bound control) on an entity, for every field which was changed during the edit cycle, PropertyChanged is now raised. This makes bound controls reflect the reset values for the fields changed, as the fields were reset to their values prior the edit cycle was started.
- IViewProjectionData doesn’t have a method CreateDataRelations anymore. This method has been moved to the new GeneralUtils class as a static method.
- Hierarchical projections from entity collections to DataSet don’t clear the DataSet’s Tables collection anymore, so if you pass a DataSet with tables, they won’t be removed.
- .NET 2.0+: TypedListBase, TypedListBase2 and TypedViewBase are now generic classes.
- When a project is re-generated into an existing directory in which the code of a previous generation cycle is located, the cs/vbproj file(s) won’t get their rootnamespace set again. Initially when a cs/vbproj file is generated, the rootnamespace is set, and in previous versions of LLBLGen Pro, the rootnamespace name was overwritten also if the cs/vbproj file was altered in subsequential code geneneration cycles. This overwriting has been removed: if you alter the namespace after the first code generation cycle, it won’t be reset. Normally you won’t notice this unless you add classes to the generated code yourself.
- The default culture used for XML serialization is now set to the invariant culture. This culture is controlled by the XmlHelper.CultureNameForXmlValueConversion property or the .config file setting cultureNameForXmlValueConversion. Previously it was set to the current culture of the executing thread. If you want to use a different culture you’ve to set the property or the config setting.
- The TDL statements <[IsForeignKey]> and <[If IsForeignKey]> now result in true if the relation is still visible but the field mapped onto the relation is hidden. This was previously not the case: if the field mapped onto the relation was hidden but the relation was still there, these statements would result in false.
- Oracle drivers targeting ODP.NET will now throw out stored procedures with parameters or a returnvalue of type BOOLEAN. This is because ODP.NET can't deal with BOOLEAN typed parameters on procs, so allowing them will result in runtime exceptions.
- .NET 2.0+: EntityBase/EntityBase2 no longer use the method called FlagAllFieldsAsChanged. This method was used by RollbackFields to simply raise changed events for all fields in the entity. However this is inefficient if a low number of none fields were actually changed. This has been fixed internally. So relying on the call to FlagAllFieldsAsChanged from RollbackFields is no longer going to work: the method is no longer called. The method is still there if you want to use it to flag all fields as changed.
- .NET 2.0+: EntityBase/EntityBase2 no longer raise for all fields in an entity a changed event if RollbackFields is called: they now only raise a changed event for fields which were changed due to the rollback.
Templates, generated code.
- .NET 2.0+, SqlServer: The SqlServer templates and DQE now use the DbProviderFactories class to produce connections, commands and the like based on the compatibility setting inside the DQE. This has the advantage that you can switch between SqlServer server and SqlServer CE Desktop without regenerating/recompiling any code: just change a config setting in the .config file of your application and by changing the connection string. It is however a breaking change because the CE Desktop-using developers have to use different templates: the SqlServer CE templates aren't available anymore on the .NET 2.0/3.x+ platforms. Furthermore, referencing SqlServerCe dll isn't required anymore, as long as the provider is registered in the .config file of the application or in the machine.config file of the .NET 2.0 framework. See the SqlServer CE documentation and the MSDN documentation for details about DbProviderFactories.
NOTE: if you use views, stored procedures and/or types in your sqlserver database which aren't supported in the SqlServer CE Desktop version you're using, you'll get errors at runtime. Please check this up front.
Breaking changes v2.5
Runtime libraries
- Build-in precision/scale checks for numeric values. These checks are performed automatically (unless you turn off automatic checking) to prevent
overflows in the database. For example if you define a field of type decimal in your database, with precision 10 and scale 2, and you try to store
a value 1234567.123 into this field, you'll get an exception that the value will cause an overflow as the precision/scale of the value exceed the
precision and scale of the field. Due to these automatic checks, developers don't have to write validators for every numeric field to see if there
is a possible overflow.
This feature can break existing applications at runtime because suddenly values like 10.500 are rejected while they were acceptable in previous versions. To overcome this, a global static (shared) property on the EntityBase(2) classes, called ScaleOverflowCorrectionActionToUse is added which accepts one of the 3 different values (None ( throw exception on scale overflow), Truncate (default, which truncates the fraction to fit the scale) or Round (which rounds the fraction using Math.Round)). This property is also settable using a config file setting by adding a line to appSettings in the config file of your application with as key scaleOverflowCorrectionActionToUse and as value 0, 1, or 2, which represent None, Truncate or Round.
- .NET 2.0/3.0 specific: every entity class (except subtypes of course, which derive from their supertype's class) now derives
from the new CommonEntityBase class, which is a generated partial class which is placed between the generated entity class and EntityBase(2).
If you're using your own preset, you have to add a new task to the preset to make your code work: the CommonEntityBase class has to be
generated. All standard presets shipped with LLBLGen Pro already have the CommonEntityBase task added to them, this requirement is solely for
custom presets, which also means modified standard presets which have been saved under a different name.
To generate the CommonEntityBase class automatically using your custom preset, you've to add a new task to that preset:
please load a project and press F7 to open the generator configuration dialog. Go to tab 3 and select the preset to alter. In the run queue, select
the task which generates the entities (EntityClassesGenerator task) and click Add Tasks. For adapter, please check the checkbox in front of the task
SD.Tasks.Adapter.CommonEntityBaseGenerator and click OK. For Selfservicing, please check the checkbox in front of the task
SD.Tasks.SelfServicing.CommonEntityBaseGenerator and click OK. The CommonEntityBase task is now added to your preset and you should now save the
preset by clicking 'Save' at the top of the dialog.
- ScalarQueryExpression no longer forces a TOP 1 (or equivalent on databases without TOP, like Oracle) clause in the query. TOP 1 severily
slowed down execution time and it also gave errors on Oracle if the ScalarQueryExpression was correlated. The TOP 1 clause is still
enforceable, a new overload to the CTor has been added which accepts a boolean for forceRowLimit (default: false). If you set this
parameter to true, you'll get a TOP 1 (or equivalent) into the scalar query produced. You can also use the property ForceRowLimit to set
this flag.
- Every entity has now a method called CreateConcurrencyPredicateFactory. This could lead to code become
incompilable if you have added this method yourself. If this is the case, simply make your method override the base class' method. This method is
called at entity construction time to produce a valid ConcurrencyPredicateFactory object which is then set as the entity's ConcurrencyPredicateFactoryToUse
- The entity method SetNewFieldValue(4) (adapter: SetNewFieldValue(3) (the protected overload) is now obsolete, it's been
replaced by the SetValue(3) method. Normally you won't run into this, but if you use the protected overload please update your code to use SetValue
instead.
- The virtual overload of the method SetNewFieldValue is no longer virtual. If you did override this method, please override the OnSetValue
method or the OnSetValueComplete method instead. The normal public SetNewFieldValue(2) method is still available and not marked as obsolete.
- The UnitOfWork2 object now auto-commits the transaction it starts itself if the passed in adapter doesn't have a running transaction
active. If you relied on the fact that the transaction started by the UnitOfWork2 object wasn't autocommitted for you, you should change your calls to
UnitOfWork2.Commit(adapter, autoCommit) and pass 'false' for autoCommit.
- AcceptChanges/RejectChanges methods in EntityBase(2)/EntityFields(2)/EntityField(2) objects are now either internal or
removed. If you were using these methods in your code, please change your code to use EntityBase(2).SaveFields/RollbackFields.
- UnitOfWork(2).Commit now returns an integer which reflects the # of entities affected by the total set of actions performed. This
could break overrides of Commit(2), as that method previously had a void return type.
- Better reporting of the # of entities saved when saving collections. This could affect unittests which will now perhaps fail
because the # returned isn't the queue length anymore but the actual number of entities saved.
- If a nullable field is set to the value null / Nothing, the entity will still call the validator object set in the entity for further validation instead of simply returning true and bypassing the validator as v2.0 and earlier versions did.
- In the DataAccessAdapterBase class the following methods have been refactored and now only one overload is virtual instead of all
of the overloads. This could break code. Please override the virtual version instead.
- FetchEntity
- FetchEntityUsingUniqueConstraint
- FetchNewEntity
- FetchEntityCollection
- DeleteEntity
- In the DaoBase class, the following methods have been refactored and have lost their 'virtual' keyword or have now just 1 overload
which is virtual, or have received a new parameter. Please update your code to meet the new signatures or override a different overload.
- FetchExisting
- ExecuteSingleRowRetrievalQuery
- ExecudeMultiRowRetrievalQuery
- In PrefetchPath(2), the virtual Add() method overload is now the one with the extra parameter for excluded fields. Please update your
derived class to override the proper method.
- Adapter specific: IEntityFields2.WriteXml and IEntityField2.WriteXml have been removed and are now internal methods, because the xml writing process
has been optimized to use XmlWriter objects instead of an XmlDocument. It's recommended to write Xml from entities and entity collections instead of
directly from fields and field objects. This also counts for deserialization of XML to fields or field objects.
- In dynamic and typed lists with fields from entities which are in a hierarchy of TargetPerEntityHierarchy, the
runtime libraries now automatically add the filters for the types the fields are defined in, so you'll get the proper results instead of potentially too many
results. This could lead to different results at runtime if you didn't filter properly in your own code. It's likely you already have proper type filters
in place as otherwise the results would have been mismatching what you requested anyway. Example: a dynamic/typed list with the field FamilyCar.Brand. This
is an inherited field from CompanyCar which is the supertype of FamilyCar. By specifying this field and not CompanyCar.Brand, it signals that the
list shouldn't contain rows from types which aren't a subtype of FamilyCar or FamilyCar itself. With the automatic type filters addition, only FamilyCar
rows or rows of subtypes of FamilyCar are returned.
Templates
- Sqlserver, SelfServicing: the catalog name is now also generated into the stored procedure name for every stored procedure call. This shouldn't have that much impact, though you should be aware of the fact that if you want to call the method in a different catalog, you have to use catalog name overwriting.
Migrating generated code from any previous version to 2.0.0.0 runtime libraries
You have to re-generate the code and recompile the generated code as well as to recompile your own code which references the runtime libraries of LLBLGen Pro
(ORM Support Classes and / or DQE). Be sure you reference the
new runtime libraries.
Your code will likely not compile at this point. Don't panic, we've created a list below with the important changes in the generated code / runtime libraries.
The list is also important for code behavior changes at runtime as we made a small set of changes which could affect runtime behavior, as in: null reference exceptions
because you access a property in your code which now returns null instead of a guaranteed value.
This guide assumes you're on 1.0.2005.1. If you're on an older version, you might run into one or two breaking changes depending on the current LLBLGen Pro
version you're using, however in almost all cases these are compile time breakings, very rare and easy to fix. If you're using a lot of custom templates
it might be you will run into more problems than which are listed below, which can be solved by updating your templates, which you have to do anyway due to the
new template configuration system.
Breaking changes v2.0
General
- DataDirect is no longer supported for Oracle. If you're using DataDirect in your project, you can't upgrade to v2.0. We'll provide a migration toolkit
after v2.0 has been released to let you migrate your .lgp file to ODP.NET
- .NET 2.0: if an entity field is nullable, by default it is generated as a Nullable(of T) field. This means that if you read that field's property, you have to
read the value into a Nullable(of T) typed variable as well. You can control this through the preferences and project properties by using the
preference/project property GenerateNullableFieldsAsNullableTypes. This setting controls every new field's Generate as Nullable type setting.
By default all the fields in your project will have that setting set to true, if they're nullable and a value type. To disable nullable fields for some
fields, you can disable that for those fields in the entity editor. It's recommended to have all fields which are nullable as Nullable(Of T), and only
disable this feature if your current code misuses the default value feature of the entity fields. Please see below as well how to detect that.
A plug-in is included in the designer which allows you to set all the generate as nullable type flags of all the entity fields selected to a given value
(true/false) so you can migrate your code from 1.0.2005.1 to v2.0 more easily, as having a lot of nullable types can break a lot of code.
- An entity field's CurrentValue property is now set to null/Nothing by default, not to a default value anymore. Also, when a field is read from the database
and the value appears to be NULL, the CurrentValue property is set to null/Nothing.
- Validator classes are no longer generated by default. You have to enable that task explicitly in the preset you're using. If you're NOT re-generating
the validator classes (because for example you're not using them), you should remove the existing validator classes from the existing
generated code.
- PredicateFactory class are no longer generated by default. You have to enable that task explicitly in the preset you're using. If you're NOT re-generating
the PredicateFactory class, because you're not using its functionality in your current code, you should remove the file
FactoryClasses\PredicateFactory.cs/vb from the existing generated code.
- SortClauseFactory class are no longer generated by default. You have to enable that task explicitly in the preset you're using. If you're NOT re-generating
the SortClauseFactory class, because you're not using its functionality in your current code, you should remove the file
FactoryClasses\SortClauseFactory.cs/vb from the existing generated code.
- IEntityValidator interface has been removed, its functionality is merged with IValidator and implemented in ValidatorBase. All entities
now have a single validator for both field and entity validation. Your existing IEntityValidator implementing classes should be converted to classes
which implement the new IValidator interface.
- An entity doesn't get a validator object by default, you either have to set it manually or preferably override CreateValidator and create the
validator there.
- ASP.NET 1.x migration to ASP.NET 2.0: if you had entity collection classes dragged onto your webforms, they're no longer usable. You've to re-do
the design time databinding with LLBLGenProDataSource(2) controls. This is due to the fact ASP.NET changed the webform - control usage drastically
as well as design time databinding.
- .NET 2.0: CustomProperties property accessors and FieldCustomProperties accessors now work with Dictionary(of string, string) (object custom properties) and
Dictionary(of string, Dictionary(of string, string)) and no longer with Hashtables.
- .NET 2.0: Collection sorts using ApplySort() isn't supported any more. This is an IBindingList method and its been replaced by EntityView(2) sort
methods
- .NET 2.0: SoapFormatter isn't supported anymore (it can't deal with generics).
- Collections now always by default have DoNotPerformAddIfPresent set to false. This can lead to duplicates in a collection at runtime as Add() no longer
checks by default if an entity is already in the collection.
- .NET 2.0: Entities no longer expose FieldNameChanged events. Instead they expose PropertyChanged, a general event exposed by the INotifyPropertyChanged
interface, which is new in .NET 2.0. Code which should notify a control of a changed property, should use the new OnPropertyChanged(propertyName) method.
- The list name of an entitycollection bound to a grid has been changed to the following: the LLBLGenProEntityName of an instance created by the factory set for
the collection + "Collection". So if the factory is set to CustomerEntityFactory, the name is "CustomerEntityCollection". In adapter, this is a change, as in
adapter previously the list name was always "". This now allows you to define gridlayouts and bind them to various sets of data at runtime.
- During databinding, when an edit cycle is in progress (row editing in grid): EntityContentsChanged event of an entity is now raised after EndEdit has been
completed. This means that EntityContentsChanged is raised if a new row is been selected. A containing collection won't be notified until this event is raised.
- The passing around of IValidator objects in selfservicing fetch code has been removed: no IValidator object is passed around anymore. This can break code if
code overrides the ExecuteMultiRowRetrievalQuery routine in DaoBase or DataAccessAdapterBase.
- Entity collection classes no longer set EntityValidator instances and Validator instances on entities added to them. The two properties EntityValidatorToUse
and ValidatorToUse have been made obsolete. The warnings resulting this obsoleteness have to be corrected to make the code work again. They've been kept to
make forms still be designable in VS.NET. Entities get their validator automatically when they're instantiated, if the proper method is overriden, no longer do
they need to get their validator object set by a collection they're contained in.
- A special method is added to existing Validator classes called OriginalValidate(). In new code it's empty, but with code generated by previous versions of
LLBLGen Pro, it will contain the code originally stored inside the Validate() method. Use this special method either from an override of the Validate method
from the base class or from a partial class. If the method doesn't contain code you added yourself, you can safely ignore this method and leave it as is. If
it does contain code you added previously, you can either copy the code over to the ValidationCode region or call the OriginalValidate() method from an
override of ValidateFieldValue() to re-wire the original code to the validation framework. The OriginalValidate() method is added to preserve original code
when a user upgrades from an LLBLGen Pro version 1.0.200x.y to v2.0. It can be your code doesn't compile even if you didn't have any validator code in the
validation classes before. This is occurs if you use inheritance in your project. If so, do a global replace of the line which breaks the compile to call the
base class' ValidateFieldValue() instead of Validate().
- When an entity is deleted and a delete restriction filter was specified and no rows were affected by the delete statement, an
ORMConcurrencyException is now thrown. This wasn't the case in 1.0.200x.y code. A normal delete without a delete restriction won't throw
this exception as no restriction has been specified.
- .NET 2.0: Collection classes aren't derived from CollectionBase anymore, which means that the methods OnRemoveComplete and OnInsertComplete
aren't available anymore for you to override. Use OnEntityRemoved and OnEntityAdded instead.
- Reading a value from an entity's field property (e.g. myCustomer.CompanyName), and the entity field hasn't been set to a value (which is the case in a
new entity where the field hasn't been set to a value), an ORMInvalidFieldReadException is thrown, if the developer has set the static flag
EntityBase(2).MakeInvalidFieldReadsFatal to true (default: false). In v1 you could get away with this and use the
default value returned, but this isn't allowed anymore because nullable fields lead to different results now and that would otherwise go unnoticed when you
upgrade your project, if the exception isn't thrown. Use the flag and the exception to track down code errors after migrating your v1 solution to v2.
Example:
OrderEntity order = new OrderEntity();
DateTime date = order.OrderDate; // no exception, default
// ...
// SelfServicing should use EntityBase instead
EntityBase2.MakeInvalidFieldReadsFatal = true;
OrderEntity order = new OrderEntity();
DateTime date = order.OrderDate; // ORMInvalidFieldReadException, as OrderDate hasn't been initialized.
The exception will likely also be thrown in code like this: (selfservicing only):
CustomerEntity customer = new CustomerEntity();
OrderCollection orders = customer.Orders; // ORMInvalidFieldReadException
This is because the PK of the customer entity is used to produce the query and that field isn't been set.
The following code works:
CustomerEntity customer = new CustomerEntity(1);
OrderCollection orders = customer.Orders; // OK
The fetch works, because the PK of customer has been set to a value, so no uninitialized field values are used.
Adapter specific
- A collection doesn't have an IValidator object anymore, which means it's not passed around in fetch logic, like in
DataAccessAdapter.ExecuteMultiRowRetrievalQuery.
- Database Specific project: the file PersistenceInfoFactory.cs/vb is no longer used and should be removed. The functionality is replaced by
the code in the file PersistenceInfoProvider.cs/vb. Be sure to remove the right file, otherwise your code won't compile.
SelfServicing specific
- All Entity field persistence information is shared among each entity instance, in the form of IFieldPersistenceInfo objects. No longer is it possible to target
multiple databases in SelfServicing without name overwriting defined in the .config file.
- .NET 2.0: All generated collection classes derive from EntityCollectionBase(of T), even if the entity type is a subtype. This is because
C# and VB.NET don't support covariance: List(of String) isn't a subtype of List(of Object). This thus means that you can't cast a subtype's collection
to a supertype's collection. We tried to have as much backwards compatibility as possible so the selfservicing collections aren't generic as in:
EntityCollection(of T), but CustomerCollection, or OrderCollection, also because the generated collections have some entity type specific code in them.
If ManagerEntity is a subtype of EmployeeEntity, and thus there's an EmployeeCollection, it can't be that ManagerCollection is a subtype of
EmployeeCollection, because that would require EmployeeCollection(of T), which would break a lot of existing code.
- EntityField.Name is no longer writable. Tricks which use this feature are not possible anymore.
- The file FactoryClasses\PropertyDescriptorFactory.cs/vb is no longer used and should be removed
- Two class scenario (now called 'TwoClasses'): there's no longer a Full/Safe mode: all derived entity class files are overwritten each time the
code is being generated. If you've code placed in these derived classes and it's placed outside user code regions, you should place the code
in the user-code regions generated into the derived entity classes.
You can switch on the feature to not overwrite existing derived entity classes in the preset of choice: select the task which generates the
derived entity classes and in the parameter window, at the bottom specify 'true' for failWhenExistent. This isn't recommended however. It's
best to migrate the code to either using usercode regions or partial classes (.NET 2.0).
- All persistence info now contains the catalog name as it is known in the project (if applicable, like with SqlServer). This is a change from
v1.0.200x.y where the catalog name was only generated into the persistence info when 2 or more catalogs were in the project. Because the catalog name
is in the persistence info, you can't simply switch catalogs by setting a connection string, if you need to connect to a different catalog at runtime
then the one you used to create the project. To be able to do so, you need catalog name overwriting through the config file. Please see
Generated code - Application configuration through .config files for more details on this.
Note: You can request the version of the runtime libraries you're currently using in your code using:
// C#
string version = SD.LLBLGen.Pro.ORMSupportClasses.RuntimeLibraryVersion.Version + "." +
SD.LLBLGen.Pro.ORMSupportClasses.RuntimeLibraryVersion.Build;
' VB.NET
Dim version As String = SD.LLBLGen.Pro.ORMSupportClasses.RuntimeLibraryVersion.Version & "." & _
SD.LLBLGen.Pro.ORMSupportClasses.RuntimeLibraryVersion.Build
The runtime libraries have a file version attribute as well, besides the 2.6.0.0 version. You can request that version attribute's value by clicking with
the right-mousebutton on the .dll and select 'Properties' and in the dialog that pops up, select the Version tab. The version format is: 2.6.08.mmdd.