I need to model a friend relationship with Fluent NHibernate. My company model has a List<Company> Related with related companies. Relations between companies are modeled in my database in a table, related which looks like this:
customer_id | related_id
Both columns is a foreign key to the PK in my customers table.
The problem is that relations are only saved once for each pair (do you call it bi-directional?).
I'm able to change the table structure if it's easier to solve in another way.
I need to map Fluent NHibernate so that when i do customer.Related(), it generates a query like:
SELECT * FROM companies LEFT JOIN related ON customer_id = id OR related_id = id
I've tried to map this in a number of different ways, the closest i've tried is:
HasManyToMany(x => x.Related)
.Inverse()
.ParentKeyColumn("customer_id")
.ChildKeyColumn("related_id")
.Table("relations")
.Cascade.All();
However, this (of course) only maps when customer_id matches.
How do I solve this?
Edit:
I think it's similar to Fluent NHibernate: How to create one-to-many bidirectional mapping?, but it does not help me much.
I think what you want to achieve is already half way done. You've mapped 2 entities with a Many2Many relation already. I wouldn't touch mapping any further.
Instead I would query what I want thru that mapping. Something like this.
function GetRelated(long id){
return Session.Query<Related>()
.Where(r=>r.Customer.Id == id || r.Related.Id == id)
.ToList();
}
A reccomendation tho, the mapped entity's name is Related and you have a related field that might sound confusing, so I'd suggest you to rename it into something else (if possible).
Hope it helps.
Related
I've been used to this kind of convention before starting to work with Entity Framework/MVC:
tblMyItem (id, id_lookup1, val2, val3, val4...) - single, generic table
tblkLookup1 (id, val1, val2,...) - one to many relation table
tblmMyItemLookup2 (id, id_myitem, id_lookup2) - many to many relations table.
Recently I've found somewhere on the web that it's not good to create id column in tblmMyItemLookup2 when using Entity Framework, but I couldn't find more information on that. Could anyone please explain, why this is so significant?
When designing many-2-many relationship(i.e Student - Teacher) based on intermediate table (Student2Teacher) with only 2 foreign key columns, you'll end up having entities with navigation properties without intermediate table(no entity will be created for that table in context at all):
Student.Teachers <- EntityCollection<Teacher>
Teacher.Students <- EntityCollection<Student>
Meanwhile, if you add any extra field to your intermediate table, you'll have navigation properties pointing to intermediate entity:
Student.Student2Teacher
Teacher.Student2Teacher
making your querying uselessly more complex
In general we use lookup tables to macth associated records in two different tables that have a many to many relationship. For instance, let we have three tables: Students, Professors and StudentsProfessors. Since, a student can atten lesson that are serviced by many professors and a professor can teach more than one leasons then this is clearly a many to many relationship. So the lookup table called StudentsProfessors is used to match a student to her/his professors and vice versa. Now, the use of an id for each record of this lookup table is meaningless. We are not going to use this number anywhere. We just need to know that Student with studentId=10 is associated with professors with ids in (1,2,4,9). Just that and not the id of this record in the lookup table.
I have Products table and Customers table. Thus there is many to many relationship between them. This is my code to create that relationship using ModelBuilder:
modelBuilder.Entity<Customer>().
HasMany(c => c.ProductsPurchased).
WithMany(p => p.Customers).Map(m =>
m.MapLeftKey("CustomerId").
MapRightKey("ProductId").
ToTable("CustomersXProducts"));
Problem here is the Join table contains primary key of CustomerId and ProductId. This essentially means one customer can purchase the same product only one time. How can I resolve this issue? I don't want CustomerId to be a primary key in my join table.
You cannot resolve the issue with your database. You generally need some additional unique column to be primary key of your junction table or you need some addition data column to form composite key with both CustomerId and ProductId. That will lead to change in your model. You will need to expose junction table as an entity - Customer and Product entities must be related to the new entity.
Perhaps you will need this anyway. It is not very common to have such relation without any additional data. Perhaps your model needs bigger change. For example customer tracking system usually uses some form of entities like Customer, Order, OrderItem, Product so there is no relation between Customer and Product directly.
I'm trying to create a 1:m relationship using Entity Framework (.net 4.0) and am getting the following error:
App_Code.Model.msl(36,6) : error 3007: Problem in mapping fragments
starting at lines 6, 36:Column(s) [ProductId] are being mapped in
both fragments to different conceptual side properties.
What i have is a Products table, and a Features table. The idea is that Products have many Features. Products each have a ProductId, and the Features have a ProductId foreign key.
Now the catch is that the foreign key doesn't exist in sql server, and i don't want it to. If it did, then it all automagically works nicely.
In the EDMX designer, i created an association from the product to the feature entity, then edited the mapping details of the ProductFeature association to be based on the Features table, which i think would make it work.
Any ideas? Thanks very much.
This is a M x N relationship. Why? Because a feature can be assigned to more than one type of product.
You should have a table ProductFeatures like so:
ProductId FeatureId
1 1
1 2
2 1
2 2
Found one solution: delete the scalar property 'ProductId' from the feature entity:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/a71901fb-97ec-4072-949a-c0c66a9775b1
However, in the auto-generated relationships that EF gives you if you set up the foreign key in the database, the eg 'ParentId' fields are present in the child as a scalar field.
So i'm a little confused still.
-edit- Further help:
http://www.hanselman.com/blog/CreatingAnODataAPIForStackOverflowIncludingXMLAndJSONIn30Minutes.aspx
I have three tables viz: Person(PersonID(INT), Personname(varchar)) , Items(ItemID(INT), Itemname(varchar)) and PersonItemAssoc(PersonItemAssoc(Int), PersonID(INT), ItemID(INT)).
PersonItemAssoc is having many to many association for personid and Itemid.
I want to get way in which if I pass the itemId, I should get all the PersonIds which dont have an association witn this ItemId in the PersonItemAssoc table.
I am using Entity Framework 4.0.
Please suggest a way for implementing this.
var peopleWithoutItem = from p in Context.Person
where !p.PersonItems.Any(pi => pi.Item.ItemId == someItemId);
select p;
Note that if you get rid of PersonItemAssoc(int) and make the PersonItemAssoc PK the compound of PersonID and ItemID then the EF can do People to Items as a many to many, instead of two 1 to many relationships.
I'm trying to save an entity that forms part of a many-to-many relationship in the entity framework and am getting the error: Unable to update the EntitySet 'zRM_OP_defaultloccvgsMapping' because it has a DefiningQuery and no element exists in the element to support the current operation.
My google-fu is weak on this one, but I understand I may have to edit the designer code and hook up a stored procedure to manually do the insert.
My table structure looks like this:
locations:
LOCID,
blah..
coverages:
CVGID,
blah..
loccvgs:
LOCID,
CVGID (no keys)
Help!
I have this exact question, but I've come up with a solution. I'll warn you though, it's a really bad one. In my situation I have 3 tables:
Video
- VideoId , int , PK
- blah
Comment
- CommentId, int, PK
- UserId, int (user that made the comment)
- CommentText, string
VideoComments
- VideoId, int, PK
- CommentId, int, PK
First of all, for entity framework to setup the relationship correctly both columns on the association table (VideoComments in my case) must be a primary key.
That said, here is how I am adding a new comment.
public VideoDTO AddCommentToVideo(VideoDTO pVideo, CommentDTO pComment)
{
Video video = context.Videos.Where(v => v.VideoId ==
pVideo.VideoId).FirstOrDefault();
User user = context.Users.Where(u => u.UserId ==
pComment.User.UserId).FirstOrDefault();
Comment comment = new Comment();
comment.CommentText = pComment.CommentText;
comment.User = user;
comment.Videos.Add(video);
context.AddToComments(comment);
context.SaveChanges();
return pVideo;
}
This is very bad...like crossing the streams bad. I do 2 queries to get the full objects mandated by Entity Framework so I can create a new comment. I would like a better way to do this, but I don't know one. Maybe this can help.