How to build inverse relationship to Entity which has more than two relationship to it? - entity-framework

I have an entities Group and Person with relationships:
Group:
Group.leader -> Person (To One)
Group.looser -> Person (To One)
Group.others ->> Person (To Many)
In leader, looser and others set I could have different Person entities. Same Person could be leader in one group, looser in second and appears in others set in third group.
in Person entity I have To-Many relationship groups which should connect
Person:
Person.groups ->> Group (should be enough but warnings)
Because I can make only one inverse relationship I always
will have a warning "something should have inverse"
How to deal with relationships like this?
Or:
I have entities Cube, Plan and Line. Cube has relationships x, y, z, Plane x and y, Line just x. And I need to share some values between them, even sometimes mixed:
Cube:
Cube.x --> Value
Cube.y --> Value
Cube.z --> Value
Plane:
Cube.x --> Value
Cube.y --> Value
Line:
Cube.x --> Value
Value:
Value.counted -->> Line.x or Line.y, Plane.x, Cube.x, y, z, SomeAnotherEntity.neededValue

Apple recommend that every relationship should have an inverse. In your case, that would mean the Person entity would have three relationships:
Person.groupsLed ->> Group (to many) // "groups where this Person is leader"
Person.groupsLost ->> Group (to many) // "groups where this person is the looser"
Person.otherGroups ->> Group (to many) // "other groups with this person as a member"
which does seem rather complicated. One alternative would be to collapse the three relationships into one (for each of Person and Group) with an intermediate entity (Ranking?):
Group.rankings ->> Ranking (to many) // "the ranking of people for this group"
Person.rankings ->> Ranking (to many) // "the ranking of this person in different groups"
In each case the inverse would be to-one:
Ranking.person -> (Person) (to one) // "the person for this ranking"
Ranking.group -> (Group) (to one) // "the group for this ranking"
You can then add an attribute to the Ranking entity to indicate the leaders/loosers/other. That could be a simple string attribute rank which takes the values "leader", "looser" or "other", or an equivalent integer enum. To manage the relationship between a Group and a Person, you add or remove Ranking objects. One downside to all this is that finding the leader or looser involves filtering the rankings, but it does give you a degree of flexibility.

Related

Equivalence relations are to Groups, as partial order relations are to...?

I'm a beginning student of category theory so the question is a little hazy. Apologies if it is too basic.
An equivalence relation induces a "symmetric category" (bad terminology?), where you can back from any arrow. The category induced by a group has a different symmetry. How are these two specifically related? Is an equivalence relation somehow an algebra, like a group, that specializes the category axioms? Is it more deeply analogous to a group in some way?
I know that a category can also be induced by a partial order - which encodes anti-symmetry rather than symmetry . Is there a corresponding algebra encoding antisymetry (like a group but encoding anti-symmetry instead)? I know a partial order itself has the algebra of a lattice.
A set with an equivalence relation is often called a setoid. Categorically, a setoid is a thin groupoid. A groupoid may be thought of as a "multi-object group" in the same way that a category is a "multi-object monoid": that is, the endomorphisms of every object in a groupoid form a group.
A partial order is a thin skeletal category (a preorder is simply a thin category). Therefore, the algebraic structure corresponding to a partial order (or preorder), in the same way that groups correspond to equivalence relations, is a monoid.
The relationship "an X is just a one-object Y" is called horizontal categorification, where for your examples we have:
X = group, Y = groupoid.
X = monoid, Y = category.

Can a relational table with just 2 attributes be in 4NF?

If there is a relation:
studentColor(studentNumber, favouriteColor)
And I have this dependency:
studentNumber -> favouriteColor
So this means a student can only have one favourite color but a favourite color can be chosen by many students, so I understand that there is a multi-value dependency:
favouriteColor ->> studentNumber
so this relation is only qualified to be in BCNF.
But I was wondering, if its:
studentNumber -> favouriteColor
favouriteColor -> studentNumber
this means that if a color is chosen by a student, it can't be picked anymore, so there isn't any multi-value dependency here.
Since I heard that a relation need to satisfy these rule to be in 4NF
It should be in the Boyce-Codd Normal Form (BCNF).
the table should not have any Multi-valued Dependency.
Does that mean it is in 4NF?
I would add what I was/is being taught in my Database Systems and Management Course
We were told that every relation that is in BNCF is not in 4NF iff
There are at least 3 attributes
There exists A ->-> B and A->->C
B and C are independent .
Here the ->-> double arrays refer to multivalued dependency.
Thus this directly leads to the conclusion that If the relation consisting of 2 attributes
is in BCNF then it is in 4NF.

Core-Data Relationships

In my application there are N number of Users. Each user can have N number of Categories. Each category can have N number of Books.
I have created following Entities BookMetadata, Users, Categories
BookMetadata entity is a unique collection of books data from different users.
How do I go about creating relationship between these entities.
Relationship between - Users & Categories.(one to many) or users & books (one to many, one user can have one or more than one book).
Relationship between - Categories & Books.(one to many).
Is my understanding about implementing these relationships correct, I'm relatively new in creating relationships in CoreData. If no or a better solution, please let me know how to go about it.
EDIT:
Consider this scenario,
User 1 -> Category 1 -> Book1,Book2.
-> Category 2 -> Book3, Book4.
User 2 -> Category 1 -> Book1,Book2,Book3.
-> Category 3 -> Book4
Here In the above scenario. The same Book (Book 3) has different category for the different user.
How to handle this scenario?
EDIT 2:
I'm attaching a sample sqlite DB file #dropbox https://www.dropbox.com/s/nlmdojkk64bkf1b/test.sqlite.
As a convention Entities should be named as singular. The relationships should be named plural or singular relative to their relationship.
From the given information it is assumed that category is created by a user to group the books like a playlist or something. A category will be unique to user and it is not shared among users. A book can be included in any number of categories.
So this will become
User < -- >> Categories
Category <-- >> Books
Book < -- >> Categories
A relation should have two sides. Inverse let you define that. If a user can have any number of categories and a category can only have one user. Inverse of categories is a user.

neo4j: one-directional / two-directional relationships?

So I looked into neo4j, and I may be using it in an upcoming project since its data model might fit my project very well. I looked through the docs but I still need an answer to this question:
Can I set relationships to be one-directional?
It seems that the neo4j people like movies so let's continue with that. If I have a graph like this:
Actor A -> [:Acts in] -> Movie B
then direction is obvious, because the nodes are different types.
But I like horror movies so...
Person A -> [:wants_to_kill] -> Person B
I need this relationship to be one-directional so if I query "Who does Person A want to kill?" I get Person B, if I query "Who does Person B want to kill?" I get nothing.
Sometimes I still need relationships to be two directional
Like:
Person A <-[:has_met] -> Person B
...which is obvious.
documentation says:
Relationships are equally well traversed in either direction. This means that there is
no need to add duplicate relationships in the opposite direction (with regard to
traversal or performance).
While relationships always have a direction, you can ignore the direction where it is
not useful in your application.
So docs say, relationships by default have an direction and I can ignore that if I wish.
Now this is where things get complicated:
Consider the following graph (and note the arrows)
Person A <- [:wants_to_kill] -> Person B
Person B -> [:wants_to_kill] -> Person C
Person C -> [:wants_to_kill] -> Person A
If I ignore the Directions for all [:wants_to_kill] I get false results
for "Who does Person A / C want to kill?"
If I knew which ones I had to ignore, I would not do the query.
So can I somehow set relationships to be two-directional (when creating them), or should I model this with two relationships (between Person A & B)?
A relationship in Neo4j always has a direction. If a relationship type's semantics do not incorporate a direction, e.g. has_met from your example, then it's best practice to apply an arbitrary direction on creation of the relationship. Querying is then done by using the "both directions" (there is no "larger/smaller than" character) notation in cypher:
start ... match (a)-[:HAS_MET]-(b) ....
In contrast, if the semantics of a relationship do have a direction like your wants_to_kill, you need to use two relationship to indicate that a and b wants kill the other one and vice versa. For the example above, you need to have 4 relationships:
Person A -[:wants_to_kill]-> Person B
Person B -[:wants_to_kill]-> Person A
Person B -[:wants_to_kill]-> Person C
Person C -[:wants_to_kill]-> Person A
To find all the person that A wants to kill you do:
start a=node:node_auto_index(name='A') match a-[:wants_to_kill]->victims_of_a return victims_of_a
To find all persons who want to kill A:
start a=node:node_auto_index(name='A') match murderer_of_a-[:wants_to_kill]->a return murderer_of_a

Entity Framework many-to-many question

Please help an EF n00b design his database.
I have several companies that produce several products, so there's a many-to-many relationship between companies and products. I have an intermediate table, Company_Product, that relates them.
Each company/product combination has a unique SKU. For example Acme widgets have SKU 123, but Omega widgets have SKU 456. I added the SKU as a field in the Company_Product intermediate table.
EF generated a model with a 1:* relationship between the company and Company_Product tables, and a 1:* relationship between the product and Company_Product tables. I really want a : relationship between company and product. But, most importantly, there's no way to access the SKU directly from the model.
Do I need to put the SKU in its own table and write a join, or is there a better way?
I just tested this in a new VS2010 project (EFv4) to be sure, and here's what I found:
When your associative table in the middle (Company_Product) has ONLY the 2 foreign keys to the other tables (CompanyID and ProductID), then adding all 3 tables to the designer ends up modeling the many to many relationship. It doesn't even generate a class for the Company_Product table. Each Company has a Products collection, and each Product has a Companies collection.
However, if your associative table (Company_Product) has other fields (such as SKU, it's own Primary Key, or other descriptive fields like dates, descriptions, etc), then the EF modeler will create a separate class, and it does what you've already seen.
Having the class in the middle with 1:* relationships out to Company and Product is not a bad thing, and you can still get the data you want with some easy queries.
// Get all products for Company with ID = 1
var q =
from compProd in context.Company_Product
where compProd.CompanyID == 1
select compProd.Product;
True, it's not as easy to just navigate the relationships of the model, when you already have your entity objects loaded, for instance, but that's what a data layer is for. Encapsulate the queries that get the data you want. If you really want to get rid of that middle Company_Product class, and have the many-to-many directly represented in the class model, then you'll have to strip down the Company_Product table to contain only the 2 foreign keys, and get rid of the SKU.
Actually, I shouldn't say you HAVE to do that...you might be able to do some edits in the designer and set it up this way anyway. I'll give it a try and report back.
UPDATE
Keeping the SKU in the Company_Product table (meaning my EF model had 3 classes, not 2; it created the Company_Payload class, with a 1:* to the other 2 tables), I tried to add an association directly between Company and Product. The steps I followed were:
Right click on the Company class in the designer
Add > Association
Set "End" on the left to be Company (it should be already)
Set "End" on the right to Product
Change both multiplicities to "* (Many)"
The navigation properties should be named "Products" and "Companies"
Hit OK.
Right Click on the association in the model > click "Table Mapping"
Under "Add a table or view" select "Company_Product"
Map Company -> ID (on left) to CompanyID (on right)
Map Product -> ID (on left) to ProductID (on right)
But, it doesn't work. It gives this error:
Error 3025: Problem in mapping fragments starting at line 175:Must specify mapping for all key properties (Company_Product.SKU) of table Company_Product.
So that particular association is invalid, because it uses Company_Product as the table, but doesn't map the SKU field to anything.
Also, while I was researching this, I came across this "Best Practice" tidbit from the book Entity Framework 4.0 Recipies (note that for an association table with extra fields, besides to 2 FKs, they refer to the extra fields as the "payload". In your case, SKU is the payload in Company_Product).
Best Practice
Unfortunately, a project
that starts out with several,
payload-free, many-to-many
relationships often ends up with
several, payload-rich, many-to-many
relationships. Refactoring a model,
especially late in the development
cycle, to accommodate payloads in the
many-to-many relationships can be
tedious. Not only are additional
entities introduced, but the queries
and navigation patterns through the
relationships change as well. Some
developers argue that every
many-to-many relationship should start
off with some payload, typically a
synthetic key, so the inevitable
addition of more payload has
significantly less impact on the
project.
So here's the best practice.
If you have a payload-free,
many-to-many relationship and you
think there is some chance that it may
change over time to include a payload,
start with an extra identity column in
the link table. When you import the
tables into your model, you will get
two one-to-many relationships, which
means the code you write and the model
you have will be ready for any number
of additional payload columns that
come along as the project matures. The
cost of an additional integer identity
column is usually a pretty small price
to pay to keep the model more
flexible.
(From Chapter 2. Entity Data Modeling Fundamentals, 2.4. Modeling a Many-to-Many Relationship with a Payload)
Sounds like good advice. Especially since you already have a payload (SKU).
I would just like to add the following to Samuel's answer:
If you want to directly query from one side of a many-to-many relationship (with payload) to the other, you can use the following code (using the same example):
Company c = context.Companies.First();
IQueryable<Product> products = c.Company_Products.Select(cp => cp.Product);
The products variable would then be all Product records associated with the Company c record. If you would like to include the SKU for each of the products, you could use an anonymous class like so:
var productsWithSKU = c.Company_Products.Select(cp => new {
ProductID = cp.Product.ID,
Name = cp.Product.Name,
Price = cp.Product.Price,
SKU = cp.SKU
});
foreach (var
You can encapsulate the first query in a read-only property for simplicity like so:
public partial class Company
{
public property IQueryable<Product> Products
{
get { return Company_Products.Select(cp => cp.Product); }
}
}
You can't do that with the query that includes the SKU because you can't return anonymous types. You would have to have a definite class, which would typically be done by either adding a non-mapped property to the Product class or creating another class that inherits from Product that would add an SKU property. If you use an inherited class though, you will not be able to make changes to it and have it managed by EF - it would only be useful for display purposes.
Cheers. :)