Invalid relationship - spring-data-neo4j

I've got a class Account like (in Groovy):
#NodeEntity
class Account {
#GraphId
Long id
String accountId
String firstname
String lastname
#Relationship(type = 'HAS_INVITED', direction = Relationship.INCOMING)
List<Account> invitations = []
String getName() {
if (firstname && lastname) {
return "$firstname ${lastname[0]}."
}
return email
}
#Override
int hashCode() {
if (id) {
return id.hashCode()
} else {
return 0
}
}
#Override
boolean equals(Object obj) {
if (obj.is(this)) {
return true
}
if (obj instanceof Account) {
return obj.id == id
}
return false
}
#Override
String toString() {
"$email"
}
}
In my database, I've created 2 accounts Chris and Bob. Bob has invited Chris like below.
To load accounts, I've written this repository:
interface AccountRepository extends GraphRepository<Account> {
Account findByAccountId(String id)
Account findByEmail(String email)
}
Now, my problem: when I load the Chris account I get Bob as invited (it's ok). But, I've got Chris as invited for Bob and I don't understand why.
For me, I should have one invitation for Chris but 0 for Bob.

Any existing setter for INCOMING relationships must be annotated to avoid ambiguity during mapping. This is specified in the documentation:
The direction attribute on a #Relationship defaults to OUTGOING. Any fields or methods backed by an INCOMING relationship must be explicitly annotated with an INCOMING direction.
http://neo4j.com/docs/ogm-manual/current/reference/#reference:annotating-entities:relationship

Related

Lambda Error: #DynamoDBIndexHashKey must specify one of HASH GSI name/names

I have the following class:
#DynamoDBTable(tableName = "PodcastReviewService-Episodes")
public class Episode {
private String podcast;
private int episodeNr;
private String name;
private int avgRating;
private String episodeId;
private List<Review> reviews;
public Episode() {}
#DynamoDBIndexHashKey(attributeName = "podcast")
public String getPodcast() {return podcast;}
#DynamoDBRangeKey(attributeName = "episodeNr")
public int getEpisodeNr() {return episodeNr;}
#DynamoDBAttribute(attributeName = "name")
public String getName() {
return name;
}
#DynamoDBIndexHashKey(attributeName = "avgRating", globalSecondaryIndexName = "avgRating")
public int getAvgRating() {
return avgRating;
}
#DynamoDBIndexRangeKey(attributeName = "episodeId", globalSecondaryIndexName = "episodeId")
public String getEpisodeId() {
return episodeId;
}
#DynamoDBAttribute(attributeName = "reviews")
public List<Review> getReviews() {
return reviews;
}
The class that attempts to add an object Episode to my DynamoDB table is :
public class EpisodeDao {
private final DynamoDBMapper dynamoDBMapper;
public EpisodeDao() {
this.dynamoDBMapper = new DynamoDBMapper(AmazonDynamoDBClientBuilder.standard().withCredentials(DefaultAWSCredentialsProviderChain.getInstance()).withRegion(Regions.US_WEST_2).build());
}
public Episode getEpisode(String podcast, int episodeNr) {
Episode episode = this.dynamoDBMapper.load(Episode.class, podcast, episodeNr);
if (episode == null) {
throw new EpisodeNotFoundException("Could not find episode of " + podcast + " nr." + episodeNr);
}
return episode;
}
public Episode saveEpisode(String podcast, String name, int episodeNr) {
Episode episode = new Episode();
//Check if episode already exists, if so return an DuplicateEpisodeException
//We initialize average rating at 0 since no reviews have been submitted
if (getEpisode(podcast, episodeNr) == null) {
episode.setPodcast(podcast);
episode.setName(name);
episode.setEpisodeNr(episodeNr);
episode.setEpisodeId(podcast.charAt(0) + name.charAt(0) + PodcastReviewsUtils.generateRandomID());
episode.setAvgRating(0);
episode.setReviews(new ArrayList<>());
} else throw new DuplicateEpisodeException("The episode that you are trying to add seems to already exist.");
return episode;
}
This is the output I get on Lambda:
"errorMessage": "#DynamoDBIndexHashKey must specify one of HASH GSI name/names",
"errorType": "com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException",
"stackTrace": [
"com.amazonaws.services.dynamodbv2.datamodeling.StandardAnnotationMaps$FieldMap.globalSecondaryIndexNames(StandardAnnotationMaps.java:345)",
"com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel$Properties$Immutable.<init>(DynamoDBMapperFieldModel.java:459)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$Bean.<init>(StandardBeanProperties.java:92)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$Bean.<init>(StandardBeanProperties.java:86)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$BeanMap.putOrFlatten(StandardBeanProperties.java:217)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$BeanMap.putAll(StandardBeanProperties.java:207)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$BeanMap.<init>(StandardBeanProperties.java:198)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$CachedBeans.getBeans(StandardBeanProperties.java:55)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties$CachedBeans.access$100(StandardBeanProperties.java:48)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardBeanProperties.of(StandardBeanProperties.java:42)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$TableBuilder.<init>(StandardModelFactories.java:132)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$TableBuilder.<init>(StandardModelFactories.java:116)",
"com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$StandardTableFactory.getTable(StandardModelFactories.java:107)",
"com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.getTableModel(DynamoDBMapper.java:409)",
"com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.load(DynamoDBMapper.java:447)",
"com.amazonaws.services.dynamodbv2.datamodeling.AbstractDynamoDBMapper.load(AbstractDynamoDBMapper.java:85)",
"com.podcast_reviews_service.dynamodb.EpisodeDao.getEpisode(EpisodeDao.java:35)",
"com.podcast_reviews_service.dynamodb.EpisodeDao.saveEpisode(EpisodeDao.java:50)",
"com.podcast_reviews_service.activity.AddEpisodeActivity.handleRequest(AddEpisodeActivity.java:35)",
"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)",
"java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)",
"java.base/java.lang.reflect.Method.invoke(Unknown Source)"
]
I haven't yet implemented the class that utilizes the GSI. I tried without the secondary index annotation but since my table has them I get the same error.
The error makes me think that I either annotated the Episode class wrong or I'm sending a null value as HASH key for the GSI, which I'm pretty sure I'm not.
You must define the name of your index for the indexhashkey.
#DynamoDBIndexHashKey(attributeName = "podcast",globalSecondaryIndexNames={ "my-index-name"})
public String getPodcast() {return podcast;}

Contact phone numbers Lync SDK 2013

Hello I'm using Lync SDK 2013, to display number phones from contact in ListBox, and use the Items (phone number) to call this number by my API. So i did a WPF application, that contains just a ListBox, and 2 buttons (Call - Hang up). My apllication is added as custom command in Lync, in RightClick in the contact. and it doesn't have any Lync Controls. So what i want to do is: if i Right Click on the contact, my application launches and gives me the number phone List in the ListBox. I did it with a WPF that contains the controls: ContactSearchInputBox (to search a contact) and ContactSearchResultList and it works very Well, I don't know how to do it without controls.
Any One Can Help Me !!!! :(
You need to read and understand the Lync SDK 2013 Lync Contact documentation.
If you wish to "simulate" the Lync Contact "search" (as per the Client search) then you need to look into the search API.
The other concepts you need to understand is the results returned from all the API are NOT guaranteed to return all the Lync Contact data that asked for.
There is no way with the Lync SDK to "load" all the contact information which is what most people seem to not understand.
The results returned are what the local cache has and no more. To get the all the Lync Contact information you need to understand the ContactSubscription model.
For each Lync Contact that you wish to be notified of field updates (or loads) you "subscribe" to the Lync Contact and then you will be notified via the Contact.ContactInformationChanged event.
So your UI must to able to auto-update the information as the fields get loaded / updated from any initial value returned from any Lync Contact value.
public partial class ChoosePhoneNumber : Window
{
LyncClient lync_client;
Contact contact;
ContactSubscription contact_subscription;
List<ContactInformationType> contact_information_list;
ContactManager contact_manager;
public ChoosePhoneNumber()
{
InitializeComponent();
connect_lync();
get_subscribed_contact(this.contact);
}
}
private void connect_lync()
{
try
{
lync_client = LyncClient.GetClient();
contact_manager = lync_client.ContactManager;
}
catch (ClientNotFoundException)
{
MessageBox.Show("Client is ot running", "Error While GetClient", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void get_subscribed_contact(Contact contact)
{
List<object> contact_phone_numbers_list = new List<object>();
contact_information_list = new List<ContactInformationType>();
contact_information_list.Add(ContactInformationType.ContactEndpoints);
contact_information_list.Add(ContactInformationType.DisplayName);
contact = contact_manager.GetContactByUri("number"); // I put here the number phone of a contact in my list
contact_subscription = LyncClient.GetClient().ContactManager.CreateSubscription();
contact_subscription.AddContact(contact);
contact.ContactInformationChanged += Contact_ContactInformationChanged;
contact_subscription.Subscribe(ContactSubscriptionRefreshRate.High, contact_information_list);
List<object> endpoints = (List<object>)contact.GetContactInformation(ContactInformationType.ContactEndpoints);
var phone_numbers_list = endpoints.Where<object>(N => ((ContactEndpoint)N).Type == ContactEndpointType.HomePhone ||
((ContactEndpoint)N).Type == ContactEndpointType.MobilePhone || ((ContactEndpoint)N).Type == ContactEndpointType.OtherPhone
|| ((ContactEndpoint)N).Type == ContactEndpointType.WorkPhone).ToList<object>();
var name = contact.GetContactInformation(ContactInformationType.DisplayName);
if (phone_numbers_list != null)
{
foreach (var phone_number in phone_numbers_list)
{
contact_phone_numbers_list.Add(((ContactEndpoint)phone_number).DisplayName);
}
conboboxPhoneNumbers.ItemsSource = contact_phone_numbers_list;
}
}
private void Contact_ContactInformationChanged(object sender, ContactInformationChangedEventArgs e)
{
var contact = (Contact)sender;
if (e.ChangedContactInformation.Contains(ContactInformationType.ContactEndpoints))
{
update_endpoints(contact);
}
}
private void update_endpoints(Contact contact)
{
if ((lync_client != null) && (lync_client.State == ClientState.SignedIn))
{
ContactEndpoint endpoints = (ContactEndpoint)contact.GetContactInformation(ContactInformationType.ContactEndpoints);
}
}
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
App.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; ;
try
{
string argsParam = "Contacts=";
if (e.Args.Length > 1)
{
if (e.Args[2].Contains(argsParam))
{
var contacts_sip_uri = e.Args[2].Split('<', '>')[1];
Params.contacts = contacts_sip_uri;
}
}
}
catch (Exception ex)
{
MessageBox.Show("Reading Startup Arguments Error - " + ex.Message);
}
}
private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
string message = e.Exception.Message;
if (e.Exception.InnerException != null)
{
message += string.Format("{0}Inner Exception: {1}", Environment.NewLine, e.Exception.InnerException.Message);
}
MessageBox.Show(message, "Unhandled Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
Params is a public static class that contains just contact as public static string contacts { get; set; }
public static class ParamContact
{
public static string contacts { get; set; }
}

Accessing public information using a specific userID on facebook graph api

Someone is logged into my app. I need to display some profiles of people that might not be on this person's friends list. Is that possible, or is it a privacy issue. A person's "public profile" should be accessible right?
I tried to get the first name, profile picture and gender
Bundle parameters = new Bundle();
parameters.putString("fields", "first_name,gender");
try {
new GraphRequest(
AccessToken.getCurrentAccessToken(),
"/" + user.getUserID(),
parameters,
HttpMethod.GET,
new GraphRequest.Callback() {
public void onCompleted(GraphResponse response) {
JSONObject facebookResponse = response.getJSONObject();
try {
final String first_name = facebookResponse.getString("first_name");
final String gender = facebookResponse.getString("gender");
Bundle params = new Bundle();
params.putBoolean("redirect", false);
params.putString("type", "square");
params.putInt("width", 200);
params.putInt("height", 200);
new GraphRequest(
AccessToken.getCurrentAccessToken(),
"/" + user.getUserID() + "/picture",
params,
HttpMethod.GET,
new GraphRequest.Callback() {
public void onCompleted(GraphResponse response) {
JSONObject facebookResponse = response.getJSONObject();
try {
JSONObject data = facebookResponse.getJSONObject("data");
String url = data.getString("url");
Name.setText(first_name);
Gender.setText(gender);
mNetworkImageView.setImageUrl(url, mImageLoader);
facebookResponseListener.updatedUserObject(first_name, url, gender, pos);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
).executeAsync();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
).executeAsync();
} catch (Exception uee) {
uee.printStackTrace();
}
all of this is inside the getView() if a listview (it's where I display the profiles). While testing, I'm getting all the information of the friends of the logged in person, but the "gender" property in the response object is missing from the non-friend. Only the name and userID is being returned.
It's all explained in the docs (https://developers.facebook.com/docs/facebook-login/permissions):
gender & locale can only be accessed if:
The person queried is the person using the app.
The person queried is using the app, and is a friend of the person
using the app.
The person queried is using the app, is not a friend of the person
using the app, but the app includes either an app access token or an
appsecret_proof argument with the call.

Birthday of Friend's using facebook api 2.0

I am trying to get birthday of my friends, those who have installed my sample app. Below is my code.
new Request(simpleFacebook.getSession(), "/" + id, null, HttpMethod.GET,
new Request.Callback() {
#Override
public void onCompleted(Response response) {
String rawResponse = response.getRawResponse();
AppLog.showLog(TAG, "Friend response is " + rawResponse);
}
}
).executeAsync();
But in response there is no any "birthday" filed.
I also used simplefacebook library. Using below code
PictureAttributes pictureAttributes = Attributes.createPictureAttributes();
pictureAttributes.setType(PictureAttributes.PictureType.SQUARE);
pictureAttributes.setWidth(250);
pictureAttributes.setHeight(250);
Profile.Properties properties = new Profile.Properties.Builder()
.add(Profile.Properties.NAME)
.add(Profile.Properties.BIRTHDAY)
.add(Profile.Properties.PICTURE)
.add(Profile.Properties.ID)
.build();
simpleFacebook.getProfile(id, properties, new OnProfileListener() {
#Override
public void onComplete(Profile response) {
String id = response.getId();
String name = response.getName();
String birthday = response.getBirthday();
String pictureUrl = response.getPicture();
AppLog.showLog(TAG, "Single friend Detail: " + id + "\t" +
name + "\t" + birthday + "\t" + pictureUrl);
FbFriendsDao fbFriendsDao = new FbFriendsDao(LoginActivity.this);
fbFriendsDao.openForWrite();
fbFriendsDao.insertFriends(new FbFriendDto(id, name, birthday, pictureUrl));
}
#Override
public void onException(Throwable throwable) {
super.onException(throwable);
}
#Override
public void onFail(String reason) {
super.onFail(reason);
}
#Override
public void onThinking() {
super.onThinking();
}
});
But it gives null in birthday filed.
Please help to solve this problem. Thanks in advance.
As #luschn mentioned, all friends_* permissions have been removed, including friends_birthday.
However it is still possible to get some data if:
The friend you want the birthday for is also a user of your app
The friend has provided the user_birthday permission (note you'll need this approved by FB)
You can do this by adding "birthday" to the fields key in me/friends:
me/friends?fields=id,name,birthday
Alternatively, you could simply save the user data to your own database when the user signs up and then retrieve it later, which would give you exactly the same outcome.
Check out the changelog: https://developers.facebook.com/docs/apps/changelog
All friends_* permissions have been removed
That includes friends_birthday, so it is not possible to get the birthday of a friend anymore.

How to map and test a "Many to Many Relationship" in NHibernate using Fluent NHibernate

When I test my many to many classes an error occurs:
System.ApplicationException: Actual
count does not equal expected count.
Entities:
public interface IEntity
{
int Id { get; set; }
}
public abstract class Entity : IEntity
{
public virtual int Id { get; set; }
public virtual bool IsPersistent
{
get { return isPersistentObject(); }
}
public override bool Equals(object obj)
{
if (isPersistentObject())
{
var persistentObject = obj as Entity;
return (persistentObject != null) && (Id == persistentObject.Id);
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return isPersistentObject() ? Id.GetHashCode() : base.GetHashCode();
}
private bool isPersistentObject()
{
return (Id != 0);
}
}
public class Team : Entity
{
public virtual string Name { get; set; }
public virtual ISet<Employee> Employees { get; set; }
public Team()
{
Employees = new HashedSet<Employee>();
}
}
public class Employee : Entity
{
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual ISet<Team> Teams { get; set; }
public virtual string EMail { get; set; }
public Employee()
{
Teams = new HashedSet<Team>();
}
}
Mappings:
public class TeamMap : ClassMap<Team>
{
public TeamMap()
{
// identity mapping
Id(p => p.Id).Column("TeamID");
// column mapping
Map(p => p.Name);
// relationship mapping
HasManyToMany(m => m.Employees)
.Table("EmployeeTeam")
.LazyLoad()
.Cascade.SaveUpdate()
.AsSet()
.ParentKeyColumn("TeamID")
.ChildKeyColumn("EmployeeID");
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
// identifier mapping
Id(p => p.Id).Column("EmployeeID");
// column mapping
Map(p => p.EMail);
Map(p => p.LastName);
Map(p => p.FirstName);
// relationship mapping
HasManyToMany(m => m.Teams).Table("EmployeeTeam")
.Inverse()
.Cascade.SaveUpdate()
.AsSet()
.LazyLoad()
.ParentKeyColumn("EmployeeID")
.ChildKeyColumn("TeamID");
}
}
Test:
[TestMethod]
public void CanCorrectlyMapEmployee()
{
var team = new List<Team> {new Team() {Name = "Team1"}};
new PersistenceSpecification<Employee>(_session)
.CheckProperty(p => p.EMail, "Mail")
.CheckProperty(p => p.FirstName, "Firstname")
.CheckProperty(p => p.Id, 1)
.CheckProperty(p => p.LastName, "Lastname")
.CheckList(p => p.Teams,team )
.VerifyTheMappings();
}
Whether I add an Employee or a Team my EmployeeTeam table is always empty.
I have tested it against SQLLite with FNH and manually against SQL Server 2008.
Does anybody of you have an idea to fix this?
edit:
I was amazed to find out that when I create an Employee and add 2 Teams to the Employee and load the created Employee he has 2 Teams. So it works fine. But when I look in my relationsip table EmployeeTeam then everything is empty. Can someone explain me why?
And does anybody know how I can use Fluent NHibernate to test my many to many relationship?
Thanks in advance!
Employee map has inverse attribute. As you probably know, this means that when you save employee, relationship table (EmployeeTeam) will not be updated. To add/remove new relationship information you have to add employee to the Team and save Team.
So, in your case - don't test many to many on the side of employee, test it on the side of team. (If you'd like NHibernate to add records when you add team to employee, you'll have to invert "Inverse" attributes - give it to team, not employee, but then - same story with Team entity).
Why were you able to load Employee with teams? Because of session-level cache. You've probably saved and loaded Employee in the same ISession - this means that NHibernate returned you exactly reference to the same object, without loading it from the db. Try saving & loading in two different sessions and you'll see no team in Employee.Teams set.
Side note: It is considered a good practice to create methods that will enforce consistency between many-to-many relationships, that is - when you add Team to Employee, Employee is added to the team, sth. like this:
class Employee
{
// ...
public void AddTeam(Team team)
{
// check for null, etc.
Teams.Add(team);
team.Employees.Add(this);
}
}
and very simillar method in the Team class.