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 v4.1 templates and
updated runtime libraries (version number: 4.1.0.0).
Before you proceed, please read the following important notice:
Important: |
Please make backup copies of your work before migrating to v4.1. That is: make backups of your own code and the
generated code before using LLBLGen Pro v4.1. This way you can roll back to your original work and continue working with 4.0 or
earlier versions if you decide that migration to v4.1 requires more work than you anticipated and you have to complete it at a later date. |
Important: |
If you're generating new v4.1 code on top of a project generated with v4.0 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 v4.0 runtime libraries or
earlier versions. Please make sure you manually update these references to the v4.1 runtime libraries, and, if applicable, be sure to remove the references to the LinqSupportClasses
and QuerySpec assemblies as starting with LLBLGen Pro v4.0, these are now merged into the ORMSupportClasses assembly. 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, v3.0, v3.1, 3.5, 4.0 as well as the
current version, v4.1. If you're migrating from version X to v4.1, be sure you read all the breaking changes on this page
starting with the version following X up till v4.0 included. 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 v4.0 to v4.1 runtime libraries
The following changes are breaking changes introduced by v4.1. Please
check them with your own project to make the transition as smoothly as
possible.
Breaking changes v4.1
The following breaking changes have been introduced in LLBLGen Pro Runtime Framework v4.1.
Migrating generated code from version v3.5 to v4.0 runtime libraries
To make migration as smooth as possible, perform the following steps:
- Load a copy of your LLBLGen Pro project file into the LLBLGen Pro
designer
- Right-click the project node in Project Explorer, select
'Project Settings'. Navigate to 'Code Generation -> General'
Make
sure 'clean up vs.net projects' is checked. This setting makes sure the
table valued functions factory TvfCallFactory.cs/vb (in the Factories folder) is added
automatically to the generated code.
- Generate code on top of a copy of your v3.5 code base.
- Load your project's VS.NET solution into VS.NET
- Change the references to the v4.0 runtime libraries. You can also do
this in notepad by editing the cs/vbproj file's XML.
- Remove references to LinqSupportClasses dll and QuerySpec dll as they're no longer needed.
- Selfservicing specific: If your project isn't set to cleanup the
VS.NET project automatically during code generation, you have to
manually remove the file 'TransactionComPlus.cs/vb' from the generated code project, if that class is still present.
Breaking changes v4.0
The following breaking changes have been introduced in LLBLGen Pro Runtime Framework v4.0. They are a result of refactoring a lot of code of the entity classes and related classes of both Adapter and SelfServicing for faster fetch operations. In general these breaking changes aren't affecting most users, only the people who have extended some classes or overriden the methods affected. Correcting these changes is easy and straight forward.
General breaking changes
- Entity.Validate() has been made protected. It's now a mandatory deprecated method (causes a compilation error) since v2.6 and starting with v4 the method is no longer available. EntityCore. AddInternalsToContext() now has a parameter, resetWhenNull.
- UnitOfWork(2).Commit doesn't throw ORMConcurrencyExceptions anymore if a delete of an entity doesn't succeed because the entity was already deleted and no restriction was specified. The exception is still thrown if a restriction has been specified and an entity delete results in 0 rows affected.
- Excluded fields are now enlisted in the resultset as: NULL as fieldname. This means the resultset layout is always the same, excluded fields or not. In general this isn't a breaking change,
but if you rely on the resultset not having NULL values for excluded fields, your code needs adjustment. The change was made to make the resultset always be the same, to make code consuming the resultset easier and faster.
- DbSpecificCreatorBase.CreateValidAlias(string, bool) has been removed (also from the interface IDbSpecificCreator), instead simply use CreateValidAlias(string) and in your override of that method always check for quotes. As all DQEs now check for quotes in the alias method, if you created your own DQE and used the override with the boolean parameter, use the CreateValidAlias(string) instead.
- Several virtual methods have had their signature changed due to the introduction of QueryParameters. Normally you won't notice this, unless you've overriden methods which now receive a QueryParameters object instead of a list of parameters. To fix this,refactor your override to accept the QueryParameters object, which contains all the parameter objects which were previously passed into the method.
- DynamicQueryEngineBase.CreateInsertDQ/CreateUpdateDQ always created a BatchActionQuery, even if there was just 1 target. We refactored it to let it create only a BatchActionQuery if there are multiple targets, as the code was intended to do when it was first written back in 2005. In general you won't run into this change, unless your code relies on the fact the query created is always a BatchActionQuery. Instead, use the interface IActionQuery to work with the object returned. EntityCollection<T> / entityNameCollection.AddRange(IEnumerable) now doesn't raise a ListChanged.ItemAdded event after each item added to the collection, but one ListChanged.Reset event after all items have been added. This makes sure a bound EventView(2) won't update itself after each addition but just once.
- The default compatibility level for the Firebird DQE is now Firebird2x (was Firebird15). If you're using Firebird 1.5, set the compatibility at the start of your program on the Firebird DQE's DynamicQueryEngine directly, by setting the static/shared property DynamicQueryEngine.CompatibilityLevel to FirebirdCompatibilityLevel.Firebird15. You can also do this through your application's config file. See Application configuration through the config file for details.
- Linq related: the test for correlation predicates in nested queries is now more strict: it now also tests the operator of the predicate to be 'Equal', previously it didn't do that, it accepted any Field op Field predicate, which could lead to queries being accepted but with potentially wrong query results.
Breaking changes related to refactor EntityFields for faster fetches
- EntityFields(2).Contract() and .Compact() methods are no longer supported on EntityFields(2) objects which are part of an entity object. Expand() is still supported in that situation. In practice this has no high impact on existing code as entity classes which use fields objects with extra fields added to them in code don't contract/compact.
- EntityFields(2)[index] setter won't place the specified field object on the index specified, if the fields object is part of an entity, it will copy the value instead.
- EntityFields(2).IsDirty and .State are only vaild when the fields object is part of an entity. This is logical, as they make no sense when the fields object is used to build a query.
- IEntityFieldCore no longer has the methods AcceptChange and RejectChange. The pattern in which these methods are used never really worked properly anyway, and it's highly unlikely these methods are used in user code. If you use these methods, use SaveFields/RollbackFields instead.
- EntityCore. PreProcessValueToSet and EntityCore.PostProcessValueToGet no longer accept a field instance, but instead accept the IFieldInfo object of the field. This fieldinfo object, which contains the field index, can then be used to obtain the values and field info from the Fields object. This is done to avoid unnecessary field access internally, as fields are no longer created by default inside an entity. Use the field index to obtain values from the entity.Fields object through its IEntityFieldsCore interface.
- EntityCore.OnFieldValueChanged no longer accepts a field, but instead accepts the IFieldInfo of the field which value was set.
- The virtual method ReadRowIntoFields in DataAccessAdapterBase/DaoBase been removed. The method was only called when single entities were fetched, the multi-entity fetch pipeline skipped it altogether.
How to work with the EntityFields(2) objects without using entity fields in an entity
If your code accesses the entity field objects in e.g. validators or auditors, instead of reading field properties, you can now access the values you need directly from the entity.Fields object through its IEntityFieldsCore interface, instead of obtaining the EntityField(2) object and access its properties. The reason you should use IEntityFieldsCore's methods instead of obtaining a field object from the Fields object is that entity objects no longer create entity field objects by default. They use a new internal object which is more efficient and allows faster entity materialization after a fetch. When you use entity.Fields[index] the Fields object will create a new field object for you on the fly, through which you can access the information you needed. However creating this field object is unnecessary.
In general this means you should use methods like entity.Fields.GetCurrentValue(index) instead of entity.Fields[index].CurrentValue. The latter still works, but creates an EntityField(2) object, the former doesn't. Please see for details about the IEntityFieldsCore interface, the LLBLGen Pro Runtime Framework Reference Manual (LLBLGenPro.RTL.ReferenceManual.chm).
LinqSupportClasses and QuerySpec assemblies are now merged into ORMSupportClasses assembly
Starting with v4, the SD.LLBLGen.Pro.LinqSupportClasses assembly and the SD.LLBLGen.Pro.QuerySpec assembly are now merged into the SD.LLBLGen.Pro.ORMSupportClasses assembly. This makes things easier when referencing assemblies. If you migrate an existing v2.6 or v3.x code base to v4, you have make sure the references to the LinqSupportClasses and QuerySpec assemblies are removed as they're no longer needed.
.NET 3.5 or higher is now required; no more support for .NET 2.0 or .NET 3.0.
Starting with v4, the LLBLGen Pro runtime framework is compiled against .NET 3.5, and your software therefore requires .NET 3.5 as well. If you're migrating an existing code base to v4, you have to adjust the target framework in Visual Studio to at least .NET 3.5
SD.LLBLGen.Pro.ORMSupportClasses and DQE assemblies no longer have .NETxy suffix in file/assembly name
Starting with v4, the ORMSupportClasses and DQE assemblies no longer have a .NETxy suffix in the assembly and file name. If you specify the assembly names for references in webforms, you have to adjust them so they don't contain '.NET20' anymore.
SD.LLBLGen.Pro.ODataSupportClasses is now compiled against v5.3 of the WCF Data Services Server assembly
Starting with v4, the ODataSupportClasses have been compiled against v5.3 of the WCF Data Services Server assembly available from nuget, instead of the .NET 4 version of the same assembly. Your application will therefore need to reference this same assembly (or newer) to use ODataSupportClasses. The advantage is that you get OData v3 support out of the box, while still are able to use OData v1 and v2.
TDL Interpreter / parser code freeze
Starting with v4, no new functionality, except some small changes, has been added to the TDL interpreter / TDL parser. All new functionality will be written in .lpt templates. If you use the TDL interpreter in your templates, be aware that if you want to utilize new features like Table valued functions in your TDL templates you have to rewrite them in .lpt templates instead. It's possible to use an .lpt include template inside a TDL template.
Migrating generated code from version v3.1 to v3.5 runtime libraries
The following changes are breaking changes introduced by v3.5. Please
check them with your own project to make the transition as smoothly as
possible.
Breaking changes v3.5
The following breaking changes have been introduced in LLBLGen Pro
Runtime Framework v3.5. They are a result of refactoring a lot of code of
the entity classes and related classes of both Adapter and SelfServicing
into a base class which is inherited by EntityBase and EntityBase2 so more
code is re-used. In general these breaking changes aren't affecting most
users, only the people who have extended some classes or overriden the
methods affected. Correcting these changes is easy and straight forward.
Changed method signatures
No more COM+ support
All COM+ oriented code has been deprecated and is no longer included.
This means that projects migrated to v3.5 and which are re-generated have to
get rid of the COM+ based classes (automatic in Adapter, in SelfServicing,
remove the TransactionComPlus helper class). COM+ using code should use System.Transactions instead.
ORMSupportClasses assembly is now split in two assemblies
To make the ORMSupportClasses and the generated code projects usable in
.NET 4 client profile projects, we split up the ORMSupportClasses assembly
into two assemblies:
- SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll The normal dll
which contains all the base classes for using the generated code
- SD.LLBLGen.Pro.ORMSupportClasses.Web.dll The assembly which
now contains the DataSource classes for Web usage and accompanying
designers.
The net effect is that for web projects migrated to v3.5 which use the
datasource controls, the assembly name of the datasource declaration has to
change from SD.LLBLGen.Pro.ORMSupportClasses.NET20 to
SD.LLBLGen.Pro.ORMSupportClasses.Web. Additionally, the version has to
be adjusted to v3.5.0.0.
In general this change has to be made in the web.config file of the
website. It's recommended to register the tag prefix 'llblgenpro' in the
web.config file so you'll have the reference to the assembly in just 1
location, instead of on every page where a datasource control is used. In
the case where the tag is registered on every page, the assembly name has to
be changed in every <Register> element as described above.
To perform design-time actions, the datasource controls located in
SD.LLBLGen.Pro.ORMSupportClasses.Web.dll have to be added to the toolbox,
which makes them available when a webform is opened in VS.NET.
No more design time support for Entity Collection classes.
The Entity Collection classes no longer support design-time usage through
a designer in VS.NET. In general it's not a good idea to drag an entity
collection onto a Windows Form anyway, but in the past you could do so and,
in adapter's case, get a designer which allowed you to pick the factory.
In v3.5 there's no longer design-time support for collections. In general
this shouldn't be a big problem, as best practices say you should use the
Data sources feature in VS.NET for this anyway: Instead of dragging/dropping
an entity collection, configuring it at design time and at runtime filling
it with data, do the following:
- Create a data source in the VS.NET project using the Data
menu
- Select the entity type you want to bind through the data source
- Add a BindingSource to the form you want to bind entity data.
- Select the created data source as the DataSource of the binding
source.
- Set the BindingSource as the DataSource of the control you want to
bind to.
- At runtime, bind a new entity collection to the
BindingSource instance by setting the DataSource property of the
BindingSource to the entity collection instance:
var toBind = new EntityCollection<CustomerEntity>();
// fetch it
...
// bind it to the bindingsource
myBindingSource.DataSource = toBind;
Projects migrated to v3.5 continue to work, but altering the
design-time designed collections won't work as there aren't any designers
anymore.
Obsolete methods
- The method entity.TestCurrentFieldValueForNull has
been marked Obsolete, as the method is unnecessary. It will give a
warning if you call this method in your code. Instead of calling this
method, please use entity.Field==null.
- The method entity.CheckIfCurrentFieldValueIsNull has
been marked Obsolete, as the method is unnecessary. It will give a
warning if you call this method in your code. Instead of calling this
method, please use entity.Field==null.
Migrating generated code from version v3.0 to v3.1 runtime libraries
The following changes are breaking changes introduced by v3.1. Please
check them with your own project to make the transition as smoothly as
possible.
Breaking changes v3.1
Templates
- In v3.0, when using multiple RDBMS types in a project (e.g. SqlServer and
Oracle), generating code would result in database specific vs.net projects
which have the database type name (e.g. SqlServer) twice e.g.
MyRootNamespace.SqlServerSqlServer.Persistence.csproj). This has now been
corrected. If you use multiple RDBMS types in your project and one of these
target frameworks (Linq to Sql, Entity Framework or LLBLGen Pro runtime
framework), generating code with v3.1 will result in a database specific
project name with the database type name just once (so MyRootNamespace.SqlServer.Persistence.csproj
for example). Existing solutions will refer to the old vs.net project file,
so you manually have to correct the solution.
To make it easy: before generating code with v3.1, rename your persistence projects so
that the RDBMS type name is specified just once. Do this in vs.net, so the .sln
file is updated as well. After that, regenerate code with v3.1, so the code
generator will update your existing vs.net projects.
If you dont want
this: in the preset you use, specify [databaseShortName] in the filename
parameter for the vs.net project task in the preset at the spot after [projectName]
or where the redundant name was specified. Then save the preset as a custom
preset and use this preset from now on.
Runtime libraries
- If you use type converters, make sure that they can handle
null-values: type converters now get passed in null (Nothing in VB.NET)
instead of DBNull.Value. This was actually already a breaking change in
v3.0.
- SQL Server DQE specific: The static property
DynamicQueryEngine.CompatibilityLevel has been renamed to
DynamicQueryEngine.DefaultCompatibilityLevel. A new, instance property
has been added, CompatibilityLevel which sets the compatibility level
per instance. Its not likely you run into this, as its recommended to
set the compatibility level in the config file or once through the
DataAccessAdapter class or CommonDaoBase class.
Migrating generated code from 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.
Features no longer supported in 3.0
The following features are no longer supported:
- Compact Framework. Starting with v3.0, we only support full
versions of the .NET framework
- .NET 1.0 and .NET 1.1. The LLBLGen Pro Runtime Framework v3.0
supports .NET 2.0 and higher, and no longer .NET 1.0 or .NET 1.1. This
also means there's no support for VS.NET 2002 and VS.NET 2003 anymore
- Oracle 8i. Oracle has dropped support (publically) for Oracle
8i years ago, and LLBLGen Pro v3.0 also doesn't support Oracle 8i
anymore.
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 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.