DataAccessAdapter does not contain GetFieldPersistenceInfos and no accessible extension method -error

Posts   
 
    
OKP
User
Posts: 12
Joined: 03-Mar-2022
# Posted on: 03-Mar-2022 13:11:07   

Hi,

I upgraded my llblgen version from v5.2 to v5.9.1 (latest). And at the same time migrated my entities.csproj and entitiesdbspecific.csproj files from .net4.6 to .netstandard2.0. Then I regenerated entities targeting .netstandard2.0. Now in the entitiesdbspecific -project in the DataAccessAdapter -class I get 6 errors when compiling. All the code in this class is autogenerated by llblgen. All the errors indicate missing reference to System.Data. Here's the errors :

Severity    Code    Description 
Error       CS0246  The type or namespace name 'DataTable' could not be found (are you missing a using directive or an assembly reference?) 
Error       CS0103  The name 'ConnectionState' does not exist in the current context    
Error       CS0103  The name 'ConnectionState' does not exist in the current context    
Error       CS0103  The name 'ConnectionState' does not exist in the current context    
Error       CS1061  'DataAccessAdapter' does not contain a definition for 'GetFieldPersistenceInfos' and no accessible extension method 
'GetFieldPersistenceInfos' accepting a first argument of type 'DataAccessAdapter' 
could be found (are you missing a using directive or an assembly reference?)    OK4.EntitiesDBSpecific  

Generated using is not referencing System.Data anymore, only these (see code snippet below). In the version 5.2 it generated a reference also to System.Data

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SD.LLBLGen.Pro.ORMSupportClasses;
using SD.LLBLGen.Pro.DQE.SqlServer;

Why llblgen suddenly is not referencing System.Data when generating entities? What setting am I missing here? This was not happening with version 5.2 and Framework4.6

Best Regards, OKP

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39006
Joined: 17-Aug-2003
# Posted on: 04-Mar-2022 10:06:07   

In v5.4, as documented, we moved the location of the csproj files for adapter. The csproj files are now in a different folder and your sln referencing these files has to reference the right csproj file, the ones from the new locations. Also make sure you reference the new runtime library assemblies, namely the ones for 5.9.1

Frans Bouma | Lead developer LLBLGen Pro
OKP
User
Posts: 12
Joined: 03-Mar-2022
# Posted on: 06-Mar-2022 14:10:48   

I have done the version 5.4 breaking changes regarding project files and now referencing the latest SD.LLGen.Pro.ORMSupportClasses (v5.9) from nuget. So I believe I have these things correct.

When DataAccessAdapter is generated this is the auto-generated result (see code below): Why is it that in the method ExecuteMultiRowDataTableRetrievalQuery() one parameter is DataTable tableToFill, but no reference to library it resides is generated? In other words no "using System.Data;" ?

//////////////////////////////////////////////////////////////
// <auto-generated>This code was generated by LLBLGen Pro 5.9.</auto-generated>
//////////////////////////////////////////////////////////////
// Code is generated on: 
// Code is generated using templates: SD.TemplateBindings.SharedTemplates
// Templates vendor: Solutions Design.
//////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SD.LLBLGen.Pro.ORMSupportClasses;
using SD.LLBLGen.Pro.DQE.SqlServer;

namespace OK4.Entities.DatabaseSpecific
{   
    // __LLBLGENPRO_USER_CODE_REGION_START AdditionalNamespaces
    using System.Collections.Generic;
    // __LLBLGENPRO_USER_CODE_REGION_END
    /// <summary>Data access adapter class, which controls the complete database interaction with the database for all objects.</summary>
    /// <remarks>Use a DataAccessAdapter object solely per thread, and per connection. A DataAccessAdapter object contains 1 active connection 
    /// and no thread-access scheduling code. This means that you need to create a new DataAccessAdapter object if you want to utilize
    /// in another thread a new connection and a new transaction or want to open a new connection.</remarks>
    public partial class DataAccessAdapter : DataAccessAdapterBase
    {
        /// <summary>The name of the key in the *.config file of the executing application which contains the connection string.</summary>
        /// <remarks>Default: the value set in the LLBLGen Pro project properties</remarks>
        public static string ConnectionStringKeyName="Main.ConnectionString";

        /// <summary>CTor</summary>
        public DataAccessAdapter() : this(ReadConnectionStringFromConfig(), false, null, null) { }

        /// <summary>CTor</summary>
        /// <param name="keepConnectionOpen">when true, the DataAccessAdapter will not close an opened connection. Use this for multi action usage.</param>
        public DataAccessAdapter(bool keepConnectionOpen) : this(ReadConnectionStringFromConfig(), keepConnectionOpen, null, null) { }

        /// <summary>CTor</summary>
        /// <param name="connectionString">The connection string to use when connecting to the database.</param>
        public DataAccessAdapter(string connectionString) : this(connectionString, false, null, null) { }

        /// <summary>CTor</summary>
        /// <param name="connectionString">The connection string to use when connecting to the database.</param>
        /// <param name="keepConnectionOpen">when true, the DataAccessAdapter will not close an opened connection. Use this for multi action usage.</param>
        public DataAccessAdapter(string connectionString, bool keepConnectionOpen) : this(connectionString, keepConnectionOpen, null, null) { }
        
        /// <summary>CTor.</summary>
        /// <param name="connectionString">The connection string to use when connecting to the database.</param>
        /// <param name="keepConnectionOpen">when true, the DataAccessAdapter will not close an opened connection. Use this for multi action usage.</param>
        /// <param name="catalogNameUsageSetting"> Configures this data access adapter object how to threat catalog names in persistence information.</param>
        /// <param name="catalogNameToUse"> The name to use if catalogNameUsageSetting is set to ForceName. Ignored otherwise.</param>
        /// <remarks>For backwards compatibility.</remarks>
        public DataAccessAdapter(string connectionString, bool keepConnectionOpen, CatalogNameUsage catalogNameUsageSetting, string catalogNameToUse) 
                : base(PersistenceInfoProviderSingleton.GetInstance())
        {
            InitClassPhase2(connectionString, keepConnectionOpen, catalogNameUsageSetting, SchemaNameUsage.Default, catalogNameToUse, string.Empty, null, null);
        }

        /// <summary>CTor</summary>
        /// <param name="connectionString">The connection string to use when connecting to the database.</param>
        /// <param name="keepConnectionOpen">when true, the DataAccessAdapter will not close an opened connection. Use this for multi action usage.</param>
        /// <param name="schemaNameUsageSetting">Configures this data access adapter object how to threat schema names in persistence information.</param>
        /// <param name="schemaNameToUse">Oracle specific. The name to use if schemaNameUsageSetting is set to ForceName. Ignored otherwise.</param>
        public DataAccessAdapter(string connectionString, bool keepConnectionOpen, SchemaNameUsage schemaNameUsageSetting, string schemaNameToUse) 
                : base(PersistenceInfoProviderSingleton.GetInstance())
        {
            InitClassPhase2(connectionString, keepConnectionOpen, CatalogNameUsage.Default, schemaNameUsageSetting, string.Empty, schemaNameToUse, null, null);
        }

        /// <summary>CTor.</summary>
        /// <param name="connectionString">The connection string to use when connecting to the database.</param>
        /// <param name="keepConnectionOpen">when true, the DataAccessAdapter will not close an opened connection. Use this for multi action usage.</param>
        /// <param name="catalogNameOverwrites"> The from-to name value pairs and setting for the overwriting of catalog names. Can be null.</param>
        /// <param name="schemaNameOverwrites"> The from-to name value pairs and setting for the overwriting of schema names. Can be null.</param>
        public DataAccessAdapter(string connectionString, bool keepConnectionOpen, CatalogNameOverwriteHashtable catalogNameOverwrites, SchemaNameOverwriteHashtable schemaNameOverwrites) 
                : base(PersistenceInfoProviderSingleton.GetInstance())
        {
            InitClassPhase2(connectionString, keepConnectionOpen, CatalogNameUsage.Default, SchemaNameUsage.Default, string.Empty, string.Empty, catalogNameOverwrites, schemaNameOverwrites);
        }

        /// <summary>Sets the flag to signal the SqlServer DQE to generate SET ARITHABORT ON statements prior to INSERT, DELETE and UPDATE Queries.
        /// Keep this flag to false in normal usage, but set it to true if you need to write into a table which is part of an indexed view.
        /// It will not affect normal inserts/updates that much, leaving it on is not harmful. See Books online for details on SET ARITHABORT ON.
        /// After each statement the setting is turned off if it has been turned on prior to that statement.</summary>
        /// <remarks>Setting this flag is a global change.</remarks>
        public static void SetArithAbortFlag(bool value)
        {
            DynamicQueryEngine.ArithAbortOn = value;
        }

        /// <summary>Sets the default compatibility level used by the DQE. Default is SqlServer2005. This is a global setting.
        /// Compatibility level influences the query generated for paging, sequence name (@@IDENTITY/SCOPE_IDENTITY()), and usage of newsequenceid() in inserts. 
        /// It also influences the ado.net provider to use. This way you can switch between SqlServer server client 'SqlClient' and SqlServer CE Desktop.</summary>
        /// <remarks>Setting this property will overrule a similar setting in the .config file. Don't set this property when queries are executed as
        /// it might switch factories for ADO.NET elements which could result in undefined behavior so set this property at startup of your application</remarks>
        public static void SetSqlServerCompatibilityLevel(SqlServerCompatibilityLevel compatibilityLevel)
        {
            DynamicQueryEngine.DefaultCompatibilityLevel = compatibilityLevel;
        }

        /// <summary>Creates a new Dynamic Query engine object and passes in the defined catalog/schema overwrite hashtables.</summary>
        protected override DynamicQueryEngineBase CreateDynamicQueryEngine()
        {
            return this.PostProcessNewDynamicQueryEngine(new DynamicQueryEngine());
        }

        /// <summary>Reads the value of the setting with the key ConnectionStringKeyName from the *.config file and stores that value as the active connection string to use for this object.</summary>
        /// <returns>connection string read</returns>
        private static string ReadConnectionStringFromConfig()
        {
#if NETSTANDARD || NETCOREAPP
            return RuntimeConfiguration.GetConnectionString(ConnectionStringKeyName);
#else
            return ConfigFileHelper.ReadConnectionStringFromConfig(ConnectionStringKeyName);
#endif
        }
        
        /// <summary>Sets the per instance compatibility level on the dqe instance specified.</summary>
        /// <param name="dqe">The dqe.</param>
        protected override void SetPerInstanceCompatibilityLevel(DynamicQueryEngineBase dqe)
        {
            if(_compatibilityLevel.HasValue)
            {
                ((DynamicQueryEngine)dqe).CompatibilityLevel = _compatibilityLevel.Value;
            }
        }

        private Nullable<SqlServerCompatibilityLevel> _compatibilityLevel = null;
        
        /// <summary>The per-instance compatibility level used by this DQE instance. Default is the one set globally, which is by default SqlServer2005 (for 2005+). 
        /// Compatibility level influences the query generated for paging, sequence name (@@IDENTITY/SCOPE_IDENTITY()), and usage of newsequenceid() in inserts. 
        /// It also influences the ado.net provider to use. This way you can switch between SqlServer server client 'SqlClient' and SqlServer CE Desktop.</summary>
        public Nullable<SqlServerCompatibilityLevel> CompatibilityLevel
        {
            get { return _compatibilityLevel; }
            set { _compatibilityLevel = value; }
        }


        // __LLBLGENPRO_USER_CODE_REGION_START CustomDataAccessAdapterCode

        public static Dictionary<Guid, DbCommand> s_DbCommands = new Dictionary<Guid, DbCommand>();

        public Guid? CancellationId { get; set; }

        public static object s_LockObj = new object();

        public override bool ExecuteMultiRowDataTableRetrievalQuery(IRetrievalQuery queryToExecute, DbDataAdapter dataAdapterToUse, DataTable tableToFill, IFieldPersistenceInfo[] fieldsPersistenceInfo)
        {
            if (CancellationId.HasValue)
            {
                lock (s_LockObj)
                {
                    s_DbCommands[CancellationId.Value] = queryToExecute.Command;
                }
            }
            return base.ExecuteMultiRowDataTableRetrievalQuery(queryToExecute, dataAdapterToUse, tableToFill, fieldsPersistenceInfo);
        }

        public static void CancelDBCommand(Guid cancellationId)
        {
            lock (s_LockObj)
            {
                DbCommand dbCommand;
                if (s_DbCommands.TryGetValue(cancellationId, out dbCommand))
                {
                        //Connection.State produces compiler error because reference to System.Data is missing.
                    if (dbCommand.Connection.State == ConnectionState.Open ||
                        dbCommand.Connection.State == ConnectionState.Executing ||
                        dbCommand.Connection.State == ConnectionState.Fetching)
                    {
                        dbCommand.Cancel();
                        
                    }
                }
            }
        }

        public static void RemoveDBCommand(Guid cancelId)
        {
            lock (s_LockObj)
            {
                s_DbCommands.Remove(cancelId);
            }
        }

        public string GetTableNameFromEntity(IEntity2 entity)
        {
            return this.GetFieldPersistenceInfos(entity)[0].SourceObjectName;   //This method is not found => compiler error
        }

        // __LLBLGENPRO_USER_CODE_REGION_END

    }
}

This was generated when using v5.3


//////////////////////////////////////////////////////////////
// <auto-generated>This code was generated by LLBLGen Pro 5.3.</auto-generated>
//////////////////////////////////////////////////////////////
// Code is generated on: 
// Code is generated using templates: SD.TemplateBindings.SharedTemplates
// Templates vendor: Solutions Design.
// Templates version: 
//////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.Data;   //It exists => no Errors.
using System.Data.Common;
using System.Configuration;
using SD.LLBLGen.Pro.ORMSupportClasses;
using SD.LLBLGen.Pro.DQE.SqlServer;


OKP
User
Posts: 12
Joined: 03-Mar-2022
# Posted on: 07-Mar-2022 09:13:14   

Hi,

I noticed that the error producing code was in the user code region. Ie. manually added into the file at some point in project history and never touched since. I wasn't aware of this feature and misthought that the whole code was something the new llblgen version generated differently.
But in the end it was not an llblgen issue. I managed to solve the problems I had by modifying this user block accordingly. Sorry for the inconvenience and thanks for the replies, this thread can be considered resolved.

Best Regards, OKP