I just started reading and playing with graph db and specifically Neo4j.
However I didn't encounter a solution for a use case that seems to me very common. Assume I have User object in my system and I want to maintain the relationships between users.
Examples:
User1 -> User2 - relationship sibling
UserX -> UserY - relationship parent
UserY -> UserX - relationship child
UserX -> UserZ - relationship teacher
I would like to store the relationship (the edge between the nodes) dynamically and not creating an entity with all possible relationships entities with annotation #Relationship.
Later, I would like to get a user and all his connections, but in run-time to figure out what is the type of the relationship.
Is this possible with spring data? or maybe it is not possible at all using Neo4j?
I will appreciate if you can point me to some reading for a solution to my problem.
Thank you.
It seems that you are only interested in the type of relationship after you would query for all, right?
You could use a #RelationshipEntity and add a property to it to define its type.
#RelationshipEntity(type = "USER_RELATION")
public class UserRelation {
//... #StartNode/#EndNode/#Id
private String type; // Here goes sibling, parent, etc.
}
And in your User entity you would just define one relationship.
#Entity
public class User {
// ... id, etc.
#Relationship(type = "USER_RELATION")
private List<UserRelation> userRelations;
}
This would always query every outgoing connection to another user.
Related
I have two Core Data entities, Car and Services. I want a car to have multiple services so I made the car relationship to Services a to-many Type.
If I look at my database, I have a Car table with its attributes and a Services table with its attributes, both saving to their respective tables.
The problem is that I can not figure out to get a service to attach to a car. When looking at the Services table there is a column for Car. I know that there are some methods in the Car+CoreDataProperties.swift file such as addToServices(_ value: Service) & addToServices(_ value: NSSet) but when I try to call one of those methods and pass in my service data I get this error:
CoreData: error: +[Services entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
Here's the code that invokes that error:
func saveToCoreData() {
let car = Car(context: self.moc)
let service = Services(context: self.moc)
service.date = date
service.serviceType = self.serviceType
service.serviceCost = self.serviceCost
service.serviceComplete = self.servicecComplete
let serviceData: NSSet = [service.date, service.serviceType, service.serviceCost, service.serviceComplete]
car.addToServices(serviceData)
try? self.moc.save()
}
To possibly make all of this more difficult, the data is being entered via a form I made using SwiftUI.
Check self.moc.save(). If it failed there would be no changes visible in the database.
addToServices(_ value: Service) and addToServices(_ value: NSSet) are overloaded methods. The first one adds a (single) Service object to a Car object and the second adds a set of Service objects to a Car object.
In order to set a car's service(s) you have alternative ways to do that:
A) (as mentioned by #nighttalker) car.addToServices(service)
B) car.addToServices([service])
C) A) and B) add new service(s), but if you want to replace the currently existing services, or set service(s) of a car for the first time, use: car.services = [service].
About the error: car.addToServices(serviceData) failed because serviceData is neither of type Set<Service> nor Service.
After going over GORM's documentation, I've figured out how to create one-to-one relationships between objects. However, I haven't figured out how to go about enabling my desired relationship. The relationship I'm trying to create acts as a one-to-one, but keeps previous row entries for historical purposes.
For example, a Car can have multiple owners throughout its lifetime. If I have Car and Owner domain objects, how can I specify that the most recent entry in the Owners table for a given Car ID is the correct one?
There are lots of different ways to model this. IMO, one of the most flexible approaches is:
class User {
String name
static hasMany = [ownerships: Ownership]
}
class Car {
String name
static hasMany = [ownerships: Ownership]
}
class Ownership {
Date start
Date end
static belongsTo = [owner: User, car: Car]
}
For example, when Ann sells her car to Bob, we set the end-time of Ann's Ownership record to the time of sale and save a new Ownership record for Bob with the start-time set to the time of sale.
If getting the current owner of a car is an operation we frequently need to perform, we could add a currentOwner method to Car
class Car {
String name
static hasMany = [ownerships: Ownership]
Ownership currentOwner() {
// depending on how this method is used, you might want to
// return the User instead of the Ownership
Ownership.findByEndIsNullAndCar(this)
}
}
I have a many to many relationship where entity are Employee and Department. Everything is going good but when i am trying to learn the relationship delete rules,i couldnot find out the right way.
I want to remove all the employee of the department if Entity Department gets deleted.But not those employee who are in another deparment.
Cascade Delete the objects at the destination of the relationship. For
example, if you delete a department, fire all the employees in that
department at the same time.
But i dont want to remove the employee if they are already in another department.One teacher teaching Swiftmay be in many departments "Computer","Electrical","Civil".How can i acheive that..Tried to use cascade but that removes all the Employees which i have set destination as below:
EDIT: Tried using nullify but deleting Source causes the deletion of all related Destination. However, deleting any single one Source simply causes Destination to forget about that particular Source.I gues,I need something intermediate nullify and cascade?
The following relationships will do what you want I think (I don't have the ability to test the answer here, but don't have rights to just leave a comment so you get the suggestion as an answer)
Employee -> Department Deny (can't fire an employee that is still assigned to a department).
Department -> Employee Cascade (fire all employees you can fire when the department is deleted, ie no longer has a department).
But it seems more reasonable to me set Department -> Employee to Nullify, and then make a separate scan for unassigned employees to fire outside the delete department code. This would also support general maintenance checks for employees that have had all their assignments removed.
In the case of mine i should not set the delete relationship to Cascade.But instead make both delete rule to nullify.And Check as in
class Departments: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
override func prepareForDeletion() {
for teacher in self.teachers!{
if let tempTeach = teacher as? Teachers{
if tempTeach.departments?.count == 1{
self.managedObjectContext?.deleteObject(tempTeach)
}else{
print("this teacher is assigned to another department also so dont delete it")
}
}
}
}
}
I am using Vinelab\NeoEloquent for a new project for Neo4j. I have a registration where people can supply interests (as nodes). When registering, first the user is created, then the interests are created (if they don't exist), an given a relationship of "Interested_In" from the person to the interest nodes.
Problem I am having is when the interest already exists (unique by name property) and I just want to create a relationship from the person created and the Interest node.
In my People Model I have (Since 1 person can have many interests):
public function interest(){
return $this->hasMany('App\Models\Interest','Interested_In');
}
In my create user function in my repository I have a section where it searches the Interests and returns one if one exists. Problem is I don't know how to then create the realtionship from People to Interest. I try to save it as
$interests = explode(',',$input['tags']);
$int = new NeoInterestRepository();
foreach($interests as $interest){
$existing = $int->find($interest);
if(count($existing)){
$person->interest()->save($existing);
}else{
$my_interest = $int->create($interest);
$person->interest()->save($my_interest);
}
}
But I get 'Argument 1 passed to Vinelab\NeoEloquent\Eloquent\Relations\HasOneOrMany::save() must be an instance of Illuminate\Database\Eloquent\Model, instance of Illuminate\Database\Eloquent\Collection given'
I see the associate() function but its only for BelongsTo which doesn't seem to apply.
Any ideas?
I am using Neo4jClient to write a demo. My demo has two nodes : Beer and BeerBrand and one relationship Is_Made has propertise ReleaseDay. I wrote this code to get nodes BeerBrand which made specific beer.
var isMadeBy = beer
.StartCypher("b")
.Match("b-[r:IS_MADE]->e")
.Return<Node<BeerBrand>>("e")
.Results.ToList();
Now, I want to get relationship *Is_Made*
var isMadeBy = beer
.StartCypher("b")
.Match("b-[r:IS_MADE]->e")
.Return<Relationship<IsMade>>("r")
.Results.ToList();
But, errors were thrown that
class IsMade must be non-abstract type with a public parameterless constructor
in order to use it as parameters 'TData' in the generic type or
method 'Neo4jClient.Relationship<TData>'
Can you help me to solve this problem?
There is an answer to a similar question here: Neo4jClient - Retrieving relationship from Cypher query which will give you the guide you should follow.
In essence, you need to add a Parameterless constructor to your relationship to allow the client (and in particular - JSON.NET) to be able to deserialize your relationship from what is in the DB to your code. Basically - JSON.NET can't figure out how to construct your relationship, as it doesn't know what the parameters in your constructors relate to.
You may also need to change from returning 'Relationship' to 'RelationshipInstance'.
Did you have a look at the wiki? http://hg.readify.net/neo4jclient/wiki/cypher
If you don't need the relationship Id then give that a try:
var isMadeBy = beer
.StartCypher("b")
.Match("b-[r:IS_MADE]->e")
.Return((r, e) => new {
isMadeRelationship = r.As<Node<SomeObjectWithAPublicConstructor>>()
beerBrand = e.As<Node<BeerBrand>>()
})
.Results.ToList();