Is there a pattern for declaring a computed key for a model? - python-3.x

I'd like a particular ndb.Model key's string id to be automatically set to the concatenation of two of the models' properties. These two properties are write-once, although other properties might change. This approach helps ensure that the entities are unique for these two properties.
Here's how the class might look like:
class Foo(ndb.Model):
bar: ndb.StringProperty()
baz: ndb.StringProperty()
An entity could be constructed like this:
foo = Foo(id='bar-baz', bar='bar', baz='baz')
foo.put()
Is there a pattern to automatically set that id in the model class itself, similar to a ComputedProperty?

You can use the _pre_put_hook function to set the key name as part of a put. This would also be the place to verify that bar & baz do not change as part of an update.

Related

If I return a class instance inside a class function, it creates a new object or it returns the existing object associated to that data?

For example:
class DogOwners(object): def get_this_animal(id, dog_name): return Dog(id=id, name=dog_name)
Would this return a new object or the existing one associated to the *args of get_this_animal()?
It returns the data I want but I can't tell if now I have two dogs with the same data
Any time you run Dog(...), you're creating a new object (assuming you didn't do anything special to the class to change that fact). Calling a class as a function constructs a new instance by default. You can also check this yourself using id:
# I added the necessary 'self' parameter, and changed the 'id' parameter
def get_this_animal(self, dog_id, dog_name):
new_dog = Dog(id=dog_id, name=dog_name)
print(id(self), id(new_dog)) # These will not be the same
return new_dog
That print will print two sepeate addresses/IDs, indicating that they're distinct objects. The dog_id and dog_name objects will be the same, however.
It would return a new dog with those attributes assuming that Dog(id=id, name =dog_name) is your constructor. The program doesn't have a way to instead return existing dogs with the same attributes as you've written it. If you wanted to not create a new dog then you'd need to store the data of all the dogs and search for that specific data to ensure you return the same dog. This storage and search can be done through several ways like a dictionary, array/list, and so on (likely a dictionary is better for what you're trying to do).

Not able to see the label of the Api names

SelectedFields is the list of the fields having API Name and itr the iterative variable and similarly rec is the iterator variable for the records So whenever I am using {!itr}
in the facet then it will print API name and If do not use facet then it will print label of the fields how to fix this??
<apex:repeat value="{!selectedFields}" var="itr">
<apex:column value="{!rec[itr]}">
<apex:facet name="header">
<apex:commandLink action="{!sortByColumn}" reRender="recPage">{!itr}
<apex:param name="Names" value="{!itr}" assignTo="{!sortingValues}"/>
</apex:commandLink>
</apex:facet>
</apex:column>
Can you use $SobjectType to get the field label, something like {!$ObjectType.Account.fields[itr].label}?
Alternatively in apex build a Map<String, String> where key is the api name and value is the label. Or you can even iterate over list of field tokens, not strings. sObject class supports a dynamic get with field token as param so same trick should work in VF and you can get label out of a token too.
Yeah! {!$ObjectType.Account.fields[itr].label} It is the way to get the Label from the API name of Objects and For the dynamic objects. We can use this {!$ObjectType[sObject].fields[itr].label} as it will take out the label from the API names.

How do I store Either (Key a) (Key b)?

I have the following model:
User
...
Group
...
Sharing
objectId (Either UserId GroupId)
In Sharing entity I want to store either UserId or GroupId and differentiate between them. Simply using Either doesn't work:
Not in scope: type constructor or class `UserId'
Not in scope: type constructor or class `GroupId'
Adding a new sum-type also doesn't work:
data SharingIdType = SharingUserId UserId | SharingGroupId GroupId
Not in scope: type constructor or class `SharingIdType'
Moving SharingIdType into another module isn't possible, because it uses UserId and GroupId types. The only way I see is to create an entity for each sharing type, like UserSharing/GroupSharing.
Other than that, how to approach this problem?
After searching for some time and thinking about it I concluded there are two possible solutions:
1.
If number of SharingIdTypes is static or rarely changes (means, it is OK to recompile the source to change it or alter the DB schema), the proper way to handle the problem is to have to entities for each sharing type:
User
...
Group
...
UserSharing
userId UserId
GroupSharing
groupId GroupId
Here the "sumness" of the problem is moved to DB queries. Whenever I need to find out with what something shared, I make two selectLists and query two tables instead of one.
2.
If number of SharingIdTypes needs to be altered dynamically, the SharingType entity is needed:
User
...
Group
...
SharingType
description String
Sharing
objectId SharingTypeId
This table is filled up with values corresponding to SharingIdTypes constructors:
do
insert $ SharingType "user"
insert $ SharingType "group"
Now whenever we share something, we refer SharingTypeId.

c# cast a value obtained from FieldInfo

Grade in an Enum Structure.
var y=1;
var x= (Grade)y;
I'm trying to do the same thing as the above line but with a dynamic CLASSNAME.
FieldInfo field = typeof(Person).GetField("Grade");
var x= Convert.ChangeType(y ,field.FieldType);
I tried that. this works fine but not for enums.
I think the problem is with the way you are accessing the field on the enum. Enum fields are static. By default, the Type.GetField method uses binding flags equivalent to BindingFlags.Public|BindingFlags.Instance. This won't match an enum member.
If this is the problem you are having, then you can use typeof(Person).GetField("Grade",BindingFlags.Public|BindingFlags.Static) to get the FieldInfo for the field named "Grade" on the enum type named "Person". This assumes that your model looks like:
enum Person
{
Grade
}
There's another problem with your code that is compatible with enums as well. It's not totally obvious because your example seems to treat "Grade" as both a field and an type. If my previous suggestion doesn't describe your model, and the following does, then the problem is that you are using Convert.ChangeType which in this case should give you an InvalidCastException.
You need to find a different way to cast the value to your enum. If the class name is not known at compile-time, then I would suggest using linq expressions, e.g.
Type targetEnumType = typeof(Person).GetField("Grade");
ConstantExpression runtimeValue = Expression.Constant(y);
UnaryExpression cast = Expression.Convert(runtimeValue,targetEnumType);
LambdaExpression lambda = Expression.Lambda(cast);
Delegate getTheCastValue = lambda.Compile();
object value = getTheCastValue.DynamicInvoke();
This code assumes that your model looks something like
class Person
{
public Grade Grade;
}
enum Grade
{
First = 1,
Second = 2
}
However, looking at this, it becomes obvious that if Person is a non-generic class, then you would have to know the type of the Grade field at runtime, so you are better off just doing a (Grade)y cast, like in your example.

Retrieving Properties from DbSqlQuery

Background: Project is a Data Import utility for importing data from tsv files into a EF5 DB through DbContext.
Problem: I need to do a lookup for ForeignKeys while doing the import. I have a way to do that but the retrieval if the ID is not functioning.
So I have a TSV file example will be
Code Name MyFKTableId
codevalue namevalue select * from MyFKTable where Code = 'SE'
So when I process the file and Find a '...Id' column I know I need to do a lookup to find the FK The '...' is always the entity type so this is super simple. The problem I have is that I don't have access to the properties of the results of foundEntity
string childEntity = column.Substring(0, column.Length - 2);
DbEntityEntry recordType = myContext.Entry(childEntity.GetEntityOfReflectedType());
DbSqlQuery foundEntity = myContext.Set(recordType.Entity.GetType()).SqlQuery(dr[column])
Any suggestion would be appreciated. I need to keep this generic so we can't use known type casting. The Id Property accessible from IBaseEntity so I can cast that, but all other entity types must be not be fixed
Note: The SQL in the MyFKTableId value is not a requirement. If there is a better option allowing to get away from SqlQuery() I would be open to suggestions.
SOLVED:
Ok What I did was create a Class called IdClass that only has a Guid Property for Id. Modified my sql to only return the Id. Then implemented the SqlQuery(sql) call on the Database rather than the Set([Type]).SqlQuery(sql) like so.
IdClass x = ImportFactory.AuthoringContext.Database.SqlQuery<IdClass>(sql).FirstOrDefault();
SOLVED:
Ok What I did was create a Class called IdClass that only has a Guid Property for Id. Modified my sql to only return the Id. Then implemented the SqlQuery(sql) call on the Database rather than the Set([Type]).SqlQuery(sql) like so.
IdClass x = ImportFactory.AuthoringContext.Database.SqlQuery<IdClass>(sql).FirstOrDefault();

Resources