V3 - how to retreive a db column name

Posts   
 
    
miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 09-Jul-2010 10:13:14   

Hi,

this post is related to the following post:

http://llblgen.com/tinyforum/Messages.aspx?ThreadID=17812

How can I retrieve a column name in the db? Till now I've been using a IEntityFieldCore.Name property. It works fine until I've get the column name wit _ char (ex. field_name_fts). How can I get that info from IEntityFieldCore?

Regards, MiloszeS

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 09-Jul-2010 10:22:29   

For SelfServicing:

var columnName = myEntityField.SourceColumnName;

For Adapter:

var adapter = new DataAccessAdapter();
IFieldPersistenceInfo fieldInfo = adapter.GetFieldPersistenceInfo(myEntityField);
var columnName = fieldInfo.SourceColumnName;
miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 09-Jul-2010 10:30:53   

Is it possible to access an adapter (without creating adapter) from class inheriting from Predicate. I need to get the field name in the following method.

public override string ToQueryText(bool inHavingClause)
Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 09-Jul-2010 11:12:03   

Is it possible to access an adapter (without creating adapter) from class inheriting from Predicate.

I'm sorry but I don't understand the above question.

miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 09-Jul-2010 12:18:39   

I have a situation in which I need to use two dbs. For each db I've generated seperate LLBLGen projects. Depending of db type I'm creating appriopriate DataAccessAdapter.

I Cannot just create an adapter, because the predicate is code/database independent. Also passing a DataAccessAdapter is not possible at the moment, because it's made in a separate layer. I'm creating a Filters, Relations, etc. and passing it to execute to the lower layer. I can create a delegate to pass appropriate adapter from the lower layer, but I don't like the mentioned solution. For now, I'm passing a hardcoded table name.

How are you gain an access in standard LLBLGen predicates to the column name? Are passing an adapter to them or you have some other solution?

Below is my Predicate class in which I need to retrieve a column name for a passed field.

public class PostgresqlFullTextSearchExpression : Predicate
    {
        string pattern;
        IEntityFieldCore field;

        public PostgresqlFullTextSearchExpression(IEntityFieldCore field, string pattern)
        {
            this.pattern = pattern;
            this.field = field;
        }
        
        public override string ToQueryText(bool inHavingClause)
        {
            return string.Format(@"plainto_tsquery('simple', '{0}') @@ {1} ", this.pattern, "field_name_value_fts");            
        }

        public override string ToQueryText()
        {
            return this.ToQueryText(false);
        }
    }
daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 12-Jul-2010 01:55:35   

DataAccessAdapter injects persistence information into predicates. You can access this from your predicate method using

_persistenceInfo.SourceColumnName

If you have problems please attach your custom predicate.

(Edit) It may be that the involved field participates in complex expressions. In such case is better that you use this:

string fieldName = this.DatabaseSpecificCreator.CreateFieldName(_field, _persistenceInfo, _field.Name, this.ObjectAlias, ref uniqueMarker, inHavingClause);
David Elizondo | LLBLGen Support Team
miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 12-Jul-2010 08:47:37   

The predicate is in my previous message. I'm using an adapter template in V3 version.

when I try to invoke a given method:

string fieldName = this.DatabaseSpecificCreator.CreateFieldName(this.field, this._persistenceInfo, this.field.Name, this.ObjectAlias, inHavingClause);

The compiler says that _persistenceInfo couldn't be found.

I'm inheriting from Predicate class. Maybe I should inherit from a different class?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 12-Jul-2010 08:58:22   

The _persistenceInfo field is not defined in the Predicate class, but rather you should define it in your own predicate.

You may use any of the defacto predicates source code as a guide.

miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 12-Jul-2010 10:21:58   

daelmo wrote:

DataAccessAdapter injects persistence information into predicates. You can access this from your predicate method using

_persistenceInfo.SourceColumnName

How it's injected into the predicate? I thought that it's injected using the property

IFieldPersistenceInfo PersistenceInfo

but it doesn't work.

Below is my modified predicate:

public class PostgresqlFullTextSearchExpression : Predicate
    {
        string pattern;
        IEntityFieldCore field;
        string fieldName;
        IFieldPersistenceInfo persistenceInfo;

        public PostgresqlFullTextSearchExpression(IEntityFieldCore field, string pattern, string fieldName = null)
        {
            this.pattern = pattern;
            this.field = field;
            this.fieldName = fieldName;
        }
        
        public override string ToQueryText(bool inHavingClause)
        {
            string fieldName = this.DatabaseSpecificCreator.CreateFieldName(this.field, this.persistenceInfo, this.field.Name, this.ObjectAlias, inHavingClause);
            //this.DatabaseSpecificCreator.CreateFieldName
            
            return string.Format(@"plainto_tsquery('simple', '{0}') @@ {1} ", this.pattern, string.IsNullOrWhiteSpace(this.fieldName) ? this.field.Name : fieldName);           
        }

        public override string ToQueryText()
        {
            return this.ToQueryText(false);
        }


        /// <summary>
        /// Gets / sets persistenceInfo for field
        /// </summary>
        /// <exception cref="InvalidOperationException">When a value is set for this property and this object was created using a selfservicing constructor.</exception>
        public IFieldPersistenceInfo PersistenceInfo
        {
            get
            {
                return this.persistenceInfo;
            }
            set
            {               
                this.persistenceInfo = value;
            }
        }

    }
Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 12-Jul-2010 13:16:13   

but it doesn't work.

This is not descriptive enough.

It's better that you derive from any of the available predicates and overwrite the ToQueryText() only.

But in general if you want to build a predicate that uses a database function (plainto_tsquery), you may use a DBFunctionCall, and set it as the expression used by the entityField.

this.field.SetExpression(...)

This way you won't need to get the column name to use it inside the ToQueryText, as this will be done automatically.

This expression can be set in the CTor of the predicate and hence you won't need to overwrite the ToQueryText()

miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 12-Jul-2010 13:56:01   

Walaa wrote:

but it doesn't work.

This is not descriptive enough.

Sorry simple_smile . I was wondering how PersistenceInfo is injected into Predicate. Usually there are 2 possibilities: via constructor or via properties. Because some predicates are created directly by coder using new keyword i thought that the object is injected by a property.

I've declared mentioned property, but the setter was not invoked and I have a null value when the following line (in the ToQuery()) was executed. So this is what mean saying "...doesn't work...".

string fieldName = this.DatabaseSpecificCreator.CreateFieldName(_field, _persistenceInfo, _field.Name, this.ObjectAlias, inHavingClause);

It's better that you derive from any of the available predicates and overwrite the ToQueryText() only.

But in general if you want to build a predicate that uses a database function (plainto_tsquery), you may use a DBFunctionCall, and set it as the expression used by the entityField.

this.field.SetExpression(...)

This way you won't need to get the column name to use it inside the ToQueryText, as this will be done automatically.

This expression can be set in the CTor of the predicate and hence you won't need to overwrite the ToQueryText()

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 12-Jul-2010 14:00:51   

You have quoted my message but I think you forgot to write your comment simple_smile

miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 12-Jul-2010 14:09:26   

Walaa wrote:

but it doesn't work.

This is not descriptive enough.

Sorry simple_smile . I was wondering how PersistenceInfo is injected into Predicate. Usually there are 2 possibilities: via constructor or via properties. Because some predicates are created directly by coder using new keyword i thought that the object is injected by a property.

I've declared mentioned property, but the setter was not invoked and I have a null value when the following line (in the ToQuery()) was executed. So this is what mean saying "...doesn't work...".

string fieldName = this.DatabaseSpecificCreator.CreateFieldName(_field, _persistenceInfo, _field.Name, this.ObjectAlias, inHavingClause);

It's better that you derive from any of the available predicates and overwrite the ToQueryText() only.

Great, I've inherited from _FieldCompareExpressionPredicate _and it works. The code can be found at the end of the message.

But in general if you want to build a predicate that uses a database function (plainto_tsquery), you may use a DBFunctionCall, and set it as the expression used by the entityField.

this.field.SetExpression(...)

This way you won't need to get the column name to use it inside the ToQueryText, as this will be done automatically.

This expression can be set in the CTor of the predicate and hence you won't need to overwrite the ToQueryText()

The reason why I need to create my own expression is full text search operator - "@@". That was in 2.6, but maybe now (v3) I'm wrong and this is not necessary?

The following expression is full text search expression for postgresql. Maybe it's not best written, but it works in my case. Maybe it'll be useful for someone. If it could be written better please provide some info.

public class PostgresqlFullTextSearchExpression : FieldCompareExpressionPredicate
    {
        string pattern;     

        public PostgresqlFullTextSearchExpression(IEntityFieldCore field, string pattern)
            : base(field, null, ComparisonOperator.None, null)
        {
            this.pattern = pattern;         
        }
        
        public override string ToQueryText(bool inHavingClause)
        {
            return string.Format(@"plainto_tsquery('simple', '{0}') @@ {1} ", this.pattern, this.PersistenceInfo.SourceColumnName);         
        }

        public override string ToQueryText()
        {
            return this.ToQueryText(false);
        }
    }

Best Regards, MiloszeS

PS could you provide in the "meanwhile" an information how the persistenceInfo is injected? I'm just curious simple_smile .

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 12-Jul-2010 14:18:34   

PS could you provide in the "meanwhile" an information how the persistenceInfo is injected? I'm just curious simple_smile

It gets injected by the InitClass() method which is called from the CTor of the Predicate passing whatever PersistenceInfo is passed to the CTor.

So actually its the responsibility of the caller of the class to set this value. This might be left for backward compatability only, coz we used to pass null for that parameter when we call the CTor of any predicate.

miloszes
User
Posts: 222
Joined: 03-Apr-2007
# Posted on: 12-Jul-2010 14:48:45   

Walaa wrote:

PS could you provide in the "meanwhile" an information how the persistenceInfo is injected? I'm just curious simple_smile

It gets injected by the InitClass() method which is called from the CTor of the Predicate passing whatever PersistenceInfo is passed to the CTor.

So actually its the responsibility of the caller of the class to set this value. This might be left for backward compatability only, coz we used to pass null for that parameter when we call the CTor of any predicate.

Ok,

but I've checked a mentioned method for a FieldCompareExpressionPredicate and see that there is a simple assignment. My constructor passes a null value as a persistenceInfo value, but the property is "magically" set in the background. I can't find a DI tags or method AddInjection... in the _FieldCompareExpressionPredicate _predicate.

Does anything invokes an InitClass method again, when a predicate is Executed?


private void InitClass(IEntityFieldCore field, IFieldPersistenceInfo persistenceInfo, ComparisonOperator comparisonOperator, 
            IExpression expression, bool negate, bool selfServicing, string objectAlias)
        {
            _field = field;
            _persistenceInfo = persistenceInfo;
            _comparisonOperator = comparisonOperator;
            _expression = expression;
            this.Negate=negate;
            this.SelfServicing = selfServicing;
            this.InstanceType = (int)PredicateType.FieldCompareExpressionPredicate;
            this.ObjectAlias = objectAlias;
        }
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 12-Jul-2010 17:31:06   

Persistence info is injected by the DataAccessAdapterBase.InsertPersistenceInfoObjects method and its overloads.

It's key that the Predicate derived class returns a value from the InstanceType property other than the initial value 'Undefined'. InstanceType is an int which represents a value of PredicateType.

So if you add your own predicate class, first check whether you can re-use an existing one. E.g. a fulltext search predicate which has 1 field, could re-use the existing one by overriding only the ToQueryText string.

If you have a different # of fields than the ones shipped or your predicate is different from the ones shipped, define for yourself a unique number to set InstanceType to, e.g. 1000.

In a partial class of DataAccessAdapter, override the method OnInsertPersistenceObjects. It receives the predicate to inject the persistence info for. Please look at the sourcecode of DataAccessAdapterBase.InsertPersistenceInfoObjects (IPredicateExpression) to get help in how to obtain the persistence info for the fields in your predicate. It comes down to usage of the method GetFieldPersistenceInfo().

So it should be pretty straight forward. If you can't get this to work, please let us know.

Frans Bouma | Lead developer LLBLGen Pro