I have a simple ndb model as follows:
class TaskList(ndb.Model):
title = ndb.StringProperty()
description = ndb.TextProperty()
priority = ndb.IntegerProperty()
class UserProfile(ndb.Model):
user = ndb.UserProperty()
tasks = ndb.KeyProperty(TaskList)
As known, a TaskList object will have an Entity Kind Entity Key and an ID.
Given an ID say 7.
I can very well get the object with ID 7 as follows:
task = ndb.Key(TaskList, 7).get()
But how do i get a user who has the task ID 7?
I tried:
tsk = ndb.Key(TaskList, 7).get()
user = UserProfile.query(UserProfile.tasks == tsk.key)
It works, but is there a better method?
You're nearly there - but there's no need to fetch the task, just to use its key property again:
task_key = ndb.Key(TaskList, 7)
user = UserProfile.query(UserProfile.tasks == task_key)
or equivalently:
user = UserProfile.query(UserProfile.tasks == ndb.Key(TaskList, 7))
Related
I am trying to understand this code ,this seems to be a test class,but i am having hard time to understand the code,i know conceptually how List and Map collection works in Sales force,but this seems to be little difficult to understand,
.In brief to me this seems to test a method which browses a list of CollaborationGroupMember.
For that, CollaborationGroup has been created and code tried to add one User.
can some one please take some time to make me understand the below code line by line?
Thanks in advance
#isTest
public class TestGroupFactory {
public static Map<CollaborationGroup, List<CollaborationGroupMember>> groupWithMember() {
CollaborationGroup groupe = new CollaborationGroup(Name = 'Test1', CollaborationType = 'Public');
insert groupe;
groupe = [SELECT Id, Name FROM CollaborationGroup WHERE Name = 'Test1'];
List<User> users = [SELECT Id, Name, Numero_de_plaque__c, SenderEmail
FROM User
WHERE Name = 'User User'];
List<CollaborationGroupMember> cgms = new List<CollaborationGroupMember>();
for (User u : users) {
CollaborationGroupMember cgm = new CollaborationGroupMember();
cgm.CollaborationGroupId = groupe.Id;
cgm.MemberId = u.Id;
cgms.add(cgm);
}
insert cgms;
return new Map<CollaborationGroup, List<CollaborationGroupMember>>{groupe => cgms};
}
}
It is technically a test class, but it does not perform any tests. Its purpose is to create test data for other test classes that contain test methods. The reason it has the #isTest annotation is so that it is only accessible in test context and does not count against the total test coverage of the organization.
The method shown creates a Chatter Group and adds Users to the group if they have the name "User User".
The code below inserts the Chatter Group and then retrieves it so the Id is available. I don't think the retrieval is necessary in this instance, but I'd have to test it.
CollaborationGroup groupe = new CollaborationGroup(Name = 'Test1', CollaborationType = 'Public');
insert groupe;
groupe = [SELECT Id, Name FROM CollaborationGroup WHERE Name = 'Test1'];
The next section retrieves the Users (presumably created in another test class)
List<User> users = [SELECT Id, Name, Numero_de_plaque__c, SenderEmail
FROM User
WHERE Name = 'User User'];
Then, a list of CollaborationGroupMembers is instantiated. A loop begins that iterates over every User. For each user, a new CollaborationGroupMember is instantiated and added to the list.
List<CollaborationGroupMember> cgms = new List<CollaborationGroupMember>();
for (User u : users) {
CollaborationGroupMember cgm = new CollaborationGroupMember();
cgm.CollaborationGroupId = groupe.Id;
cgm.MemberId = u.Id;
cgms.add(cgm);
}
The group members are inserted
insert cgms;
The group and group members are added to a map and returned
return new Map<CollaborationGroup, List<CollaborationGroupMember>>{groupe => cgms};
This weird case happened twice already in the last 2 days.
I used Datastore Admin to remove all entities, no more than 100, to later reāupload db using remote_api_shell but after the request the Datastore Write Operations reached the limit:
This is the first and the only operation I did since last 24h reset.
Also the error is reported in remote_api_shell when I try to put new entities.
Any advice welcome.
Edit:
Here the models, nothing huge...
class Brand(BaseModel):
'''
Brand class
`Marca` in Etax db
'''
name = db.StringProperty()
abbr = db.StringProperty()
def __repr__(self):
return ('<Brand {0} instance at {1}>'
.format(self.abbr.encode('utf-8'), hex(id(self))))
class Model(BaseModel):
'''
Model class
`Gamma` in Etax db
'''
name = db.StringProperty()
code = db.IntegerProperty()
brand = db.ReferenceProperty(Brand, collection_name='models')
def __repr__(self):
return ('<Model {0} instance at {1}>'
.format(self.code, hex(id(self))))
class TrimLevel(BaseModel):
'''
Trim Level class
`Modello` in Etax db
'''
name = db.StringProperty()
etax_code = db.IntegerProperty()
start_production_date = db.DateProperty()
end_production_date = db.DateProperty()
retail_buy_prices = db.ListProperty(int)
retail_sell_prices = db.ListProperty(int)
list_prices = db.ListProperty(int)
model = db.ReferenceProperty(Model, collection_name='trim_levels')
fuel_supply = db.StringProperty()
gear_shift = db.StringProperty()
gear_speeds = db.IntegerProperty()
doors = db.IntegerProperty()
seats = db.IntegerProperty()
kw = db.IntegerProperty()
def __repr__(self):
return ('<TrimLevel {0} instance at {1}>'
.format(self.etax_code, hex(id(self))))
If you look at billing docs, that a high-level delete takes several low-level write operations:
Entity Delete (per entity): 2 writes + 2 writes per indexed property value + 1 write per composite index value
So if 100 entity deletes used 50k write ops, it means that your every entity had 500 index entries.
This can happen when entity has large list properties or havs a compound index spanning multiple list properties (= exploding index)
Do you have any compound indexes defined? What properties does your entity have?
I'm a bit confused on how to create a "Key" object to select exactly 1 row of my Entity ("Customer").
My code :
Query query = new Query("Customer");
// **** how do I have to create this key ???
Key key = KeyFactory.createKey("Customer", 1);
// ****
FilterPredicate keyFilter = new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.EQUAL, key);
query.setFilter(keyFilter);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
PreparedQuery pq = datastore.prepare(query);
Entity customer = pq.asSingleEntity();
if (! (customer == null)) {
log.info("OK !");
}
else {
log.info("no customer found");
}
My result is always : "no customer found".
With the datastore viewer (I'm working locally) I can see 3 rows :
id/name = 1 email = "your email" name = "your name"
id/name = 2 email = "your email" name = "your name"
id/name = 3 email = "your email" name = "your name"
I want to select customer with id/name=1.
I've tried :
KeyFactory.createKey("Customer", 1);
and
KeyFactory.createKey("Customer", "your name");
but with no success.
When I do programmatically a search (asList) on "Customer" and I print the keys' values I see :
row 1 key = Customer("your name")/Customer(1)
row 2 key = Customer("your name")/Customer(2)
row 3 key = Customer("your name")/Customer(3)
The printable values of the keys are in the format : "Entity(name)/Entity(id/name)"
How can I create such key values in my code ?
On the javadoc I see only :
createKey("kind", id)
createKey("kind", "name")
The other methods require an ancestor, I've not created an ancestor ....
This is the code that I've executed to created the 3 rows (it has been executed 3 times) :
Key customerKey = KeyFactory.createKey("Customer", "your name");
Entity customer = new Entity("Customer", customerKey);
customer.setProperty("name", "your name");
customer.setProperty("email", "your email");
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(customer);
Thanks in advance !
Regards
Max
In other words, how do create a Key whose "toString" gives the following result ?
Code : log.info("customer KeyFactory.keyToString = "+KeyFactory.keyToString(key));
Output : INFO: customer KeyFactory.keyToString = Customer("your name")/Customer(1)
The creation of the Entities is not correct.
You dont have to create a key on your own.
If you create a Entity with a kind and keyname or ID parameter, a key will be created automaticlly out of the kind and the keyname or ID.
Entity customer = new Entity("Customer", "your name");
customer.setProperty("email", "your email");
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(customer);
That is all you need to create the Entity you want.
When you give a kind and a key, a child Entity will be created.
So you had created a Customer with "your name" who is a Customer with the ID 1.
To get the Entity with a key you just have to take the same parameters to create a key.
Key key = KeyFactory.createKey("Customer", "your name");
I would prefer to use get(), but i dont know what you want to do.
For Example to get the email of a Customer:
Entity e;
try {
e = datastore.get(key);
String myEmail= (String) e.getProperty("your email");
I think you want to use get() not query() when you have a Key.
https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/DatastoreService#get(com.google.appengine.api.datastore.Key)
Let us assume that you have a Java entity class called Product and you wish to retrieve a unique record given its key i.e. ID
The method would look something like this:
public Product getProduct(Long id) {
//Get Persistence Manager
PersistenceManager pm = ...;
Key k = KeyFactory.createKey(Product.class.getSimpleName(), id);
Product product = null;
try {
product = pm.getObjectById(Product.class, k);
}
finally {
pm.close();
}
return product;
}
So in your example, I think you can replace Product with your class name. I guess your class name is Customer
Hi all the below solution works in that it creates a record in the MeetingRoomRequest table and also adds the associated amenities to that request into the MeetingRoomRequestAmenityLink table. However it just feels a bit clunky, so I was wondering if there is a nicer solution out there (i.e. not having to create 2 context instances) using MVC 3 and Entity Framework??
Please note i've set up the necessary relationships (one to many) in SQL Server and Entity Framework.
Also please note AmenityList is an array of id's (e.g. [1,2,4])
private readonly IDataRepository<MeetingRoomRequest> _meetingRoomRequestRepository = new DataRepository<MeetingRoomRequest>();
private readonly IDataRepository<MeetingRoomRequestAmenityLink> _meetingRoomRequestAmenityLinkRepository = new DataRepository<MeetingRoomRequestAmenityLink>();
var meetingRoomRequestToAdd = new MeetingRoomRequest
{
User = meetingRoomRequestViewModel.User,
UserEmail = meetingRoomRequestViewModel.UserEmail,
Title = meetingRoomRequestViewModel.Title,
Comments = meetingRoomRequestViewModel.Comments,
StartDateTime = meetingRoomRequestViewModel.StartTime,
EndDateTime = meetingRoomRequestViewModel.EndTime,
RequestStatusID = (int)Enums.RequestStatus.New,
AttendeeCount = meetingRoomRequestViewModel.AttendeeCount,
AttendeeType = meetingRoomRequestViewModel.AttendeeType,
OfficeID = meetingRoomRequestViewModel.OfficeId,
LocationID = meetingRoomRequestViewModel.LocationId,
};
_meetingRoomRequestRepository.Add(meetingRoomRequestToAdd);
_meetingRoomRequestRepository.SaveChanges();
var meetingRoomRequestAdded = meetingRoomRequestToAdd;
foreach (var item in meetingRoomRequestViewModel.AmenityList)
{
var meetingRoomRequestAmenityLinkToAdd = new MeetingRoomRequestAmenityLink
{
AmenityID = item,
MeetingRoomRequestID = meetingRoomRequestAdded.MeetingRoomRequestID
};
_meetingRoomRequestAmenityLinkRepository.Add(meetingRoomRequestAmenityLinkToAdd);
_meetingRoomRequestAmenityLinkRepository.SaveChanges();
}
The way you are going about it looks right, but there are some improvements that could be made in efficiency of processing the request.
Since these are a child/parent relationship, you can create the parent entity and then attached the childern in the foreach loop before you call save changes on the parent entity. EF will automatically populate the foreign key value on the child object with the primary (or associated key) from the parent.
You can continue to use your Entity without having to save it back out to a variable. EF's object tracking will continue to track this throughout your function.
By moving the savechanges outside of the foreach loop, you are reducing the number of calls. I believe the same amount of SQL will be sent on the one final call, but you may see increases of not having the connection open/close. There may be other built in efficiencies as well from EF
The Code
var meetingRoomRequestToAdd = new MeetingRoomRequest
{
User = meetingRoomRequestViewModel.User,
UserEmail = meetingRoomRequestViewModel.UserEmail,
Title = meetingRoomRequestViewModel.Title,
Comments = meetingRoomRequestViewModel.Comments,
StartDateTime = meetingRoomRequestViewModel.StartTime,
EndDateTime = meetingRoomRequestViewModel.EndTime,
RequestStatusID = (int)Enums.RequestStatus.New,
AttendeeCount = meetingRoomRequestViewModel.AttendeeCount,
AttendeeType = meetingRoomRequestViewModel.AttendeeType,
OfficeID = meetingRoomRequestViewModel.OfficeId,
LocationID = meetingRoomRequestViewModel.LocationId,
};
_meetingRoomRequestRepository.Add(meetingRoomRequestToAdd);
foreach (var item in meetingRoomRequestViewModel.AmenityList)
{
meetingRoomRequestToAdd.MeetingRoomRequestAmenityLinks.Add(new MeetingRoomRequestAmenityLink
{
AmenityID = item
});
}
_meetingRoomRequestRepository.SaveChanges();
I have a GAE database entity that looks like this:
class Notification(db.Model):
alert = db.StringProperty()
type = db.StringProperty()
status = db.StringProperty(default="unread", choices=set(["unread", "read"]))
created = db.DateTimeProperty(auto_now_add=True)
modified = db.DateTimeProperty(auto_now=True)
entity = db.StringProperty()
record = db.ReferenceProperty(model.RecordModel)
actor = db.ReferenceProperty(model.Profile)
account = db.ReferenceProperty(model.Account)
... and I create an entity like so:
notify = model2.Notification(account=account)
notify.alert = message
notify.type = "reminder"
notify.actor = actor
notify.record = record
notify.put()
This call raises an error *'Notification' object has no attribute '_key'*
nquery = db.Query(model2.Notification).filter('account =', self.session.account).order('-created')
for n in nquery:
try:
_dict = {}
_dict['serverID'] = str(n.key()) #- raises error!
try:
nquery = Notification.all().filter('account =', self.session.account).order('-created')
I think I've figured it out! The "entity" property in my Notification class is causing some sort of naming conflict in python appengine. Changing the name removes the "error object has no attribute '_key'" error. Go figure!