Code First CTP: Multiple PKs or FKs - c#

In some instances, we may have PK/FK references duplicated, so entity A and entity B are in a PK/FK relationship, but 3 times. So entity A would have 3 FK collections and entity B would have 3 entity references. How does that work with the code-first template? Do you follow the naming convention of Entity Framework model/database first approaches (EntityA, EntityA1, etc.), and it knows how to hook those relationships up, or is there an extra step, or what?
Thanks.

If you were to define your classes like this
public class EntityA
{
public int EntityAId { get; set; }
public virtual EntityB EntityB1 { get; set; }
public virtual EntityB EntityB2 { get; set; }
public virtual EntityB EntityB3 { get; set; }
}
public class EntityB
{
public int EntityBId { get; set; }
public string Name { get; set; }
}
EF Code First would create two tables (EntityAs, EntityBs). By convection the EntityAs table would have a primary key of EntityAId and three foreign keys linking to EntityB called (EntityB1_EntityBId, EntityB2_EntityBId, EntityB3_EntityBId).
You can however override this convection by adding properties for the foreign keys and adding RelatedTo tags on the navigation properties.
For example:
public class EntityA
{
public int EntityAId { get; set; }
public int MySpecialFkName { get; set; }
[RelatedTo(ForeignKey = "MySpecialFkName")]
public EntityB EntityB1 { get; set; }
}
If you didn't want the RelatedTo meta data in your POCO class, you could instead define the relationship in the OnModelCreating method.
modelBuilder.Entity<EntityA>().HasRequired(p => p.EntityB1)
.HasConstraint((fk, pk) => fk.MySpecialFkName == pk.EntityBId);

Related

EF Code First Flexible Relationships

I'm trying to set up a flexible one-to-many relationship in EF. Imagine we have the following POCO classes:
public class EntityA
{
public Guid Id { get; set; }
public virtual IEnumerable<Event> Events { get; set; }
}
public class EntityB
{
public Guid Id { get; set; }
public virtual IEnumerable<Event> Events { get; set; }
}
public class Event
{
public Guid Id { get; set; }
public Guid EntityId { get; set; }
}
I want the Event class to link to either Entity through the EntityId propery. So it's not a normal One-To-Many relationship.
I don't need any relationship properties on the Event side, but I would like there to be an IEnumerable<Event> Events property in each of the two Entity classes, which will allow me to grab a list of linked events for any entity I choose.
I'm using EntityTypeConfiguration<T> maps but I need help working out the relationships on this.

How can I eager load objects that are referencing the primary key of my POCO class in a 1:Many relationship?

Considering the documentation here, you can define foreign key relationships in your pocos like the given example:
public class Customer
{
[References(typeof(CustomerAddress))]
public int PrimaryAddressId { get; set; }
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
This is fine, as there's a 1:1 relationship here. However, I have a 1:Many relationship I need to define, and the relationship is actually defined in the child object, not the parent object.
So, let's say I have these POCOs:
public class Customer
{
[PrimaryKey]
public int CustomerId { get; set; }
public List<CustomerAddress> CustomerAddresses { get; set; }
}
public class CustomerAddress
{
[PrimaryKey]
public int CustomerAddressId{ get; set; }
public int CustomerId { get; set; }
}
How can I have ORMLite eager load the CustomerAddresses property in the Customer POCO?
You have to call Db.LoadSelect<Customer>() method and your customer(s) will retrieve CustomerAddresses (you need to add [Reference] attribute on top of your CustomerAddresses property).

EF 6 - Cascade delete without fluent API [duplicate]

When using data annotations with EF4.1 RC is there an annotation to cause cascade deletes?
public class Category
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
Using this model the constraint generated is:
ALTER TABLE [Product] ADD CONSTRAINT [Product_Category]
FOREIGN KEY ([Category_Id]) REFERENCES [Categorys]([Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
If not how is it achieved?
Putting required on the Product table Category relationship field solves this
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[Required] //<======= Forces Cascade delete
public Category Category { get; set; }
}
I like to turn off cascade delete by default (by removing the OneToManyCascadeDeleteConvention)
I was then hoping to add them back in via annotations, but was surprised that EF doesn't include a CascadeDeleteAttribute.
After spending way too long working around EF's ridiculous internal accessor levels, the code in this gist adds a convention that allows attributes to be used: https://gist.github.com/tystol/20b07bd4e0043d43faff
To use, just stick the [CascadeDelete] on either end of the navigation properties for the relationship, and add the convention in your DbContext's OnModeCreating callback. eg:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Add<CascadeDeleteAttributeConvention>();
}
And in your model:
public class BlogPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
[CascadeDelete]
public List<BlogPostComment> Comments { get; set; }
}
Not sure on Data Annotations, but you can add it in the database by modifying the actual relationship.
Looks like the answer is no for data annotations:
http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/394821ae-ab28-4b3f-b554-184a6d1ba72d/
This question appears to show how to do it with the fluent syntax, but not sure if that applies for 4.1 RC
EF 4.1 RC: Weird Cascade Delete
As an additional example to Tyson's answer, I use the [CascadeDelete] attribute like follows in an entity, which successfully adds the "Cascade" delete rule to the Parent-Child relation.
public class Child
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[SkipTracking]
public Guid Id { get; set; }
[CascadeDelete]
public virtual Parent Parent { get; set; }
[Required]
[ForeignKey("Parent")]
public Guid ParentId { get; set; }
}

entity framework - many to many relationship

Hi I try use Many to Many relationship with EF Fluent API. I have 2 POCO classes.
public class Project
{
public int ProjectId { get; set; }
public virtual ICollection<Author> Authors { get; set; }
public Project()
{
Authors = new List<Author>();
}
}
public class Author
{
public int AuthorId { get; set; }
public virtual ICollection<Project> Projects { get; set; }
public Author()
{
Projects = new List<Project>();
}
}
And I map many to many relationship with this part of code:
////MANY TO MANY
modelBuilder.Entity<Project>()
.HasMany<Author>(a => a.Authors)
.WithMany(p => p.Projects)
.Map(m =>
{
m.ToTable("ProjectAuthors");
m.MapLeftKey("ProjectId");
m.MapRightKey("AuthorId");
});
This created table ProjectsAuthors in DB. It is my first attempt with this case of relationship mapping.
If I omitted this mapping it created table AuthorProject with similar schema. It is correct bevahior?
By trial and error I found the following. Given two classes...
public class AClass
{
public int Id { get; set; }
public ICollection<BClass> BClasses { get; set; }
}
public class BClass
{
public int Id { get; set; }
public ICollection<AClass> AClasses { get; set; }
}
...and no Fluent mapping and a DbContext like this...
public class MyContext : DbContext
{
public DbSet<AClass> AClasses { get; set; }
public DbSet<BClass> BClasses { get; set; }
}
...the name of the created join table is BClassAClasses. If I change the order of the sets...
public class MyContext : DbContext
{
public DbSet<BClass> BClasses { get; set; }
public DbSet<AClass> AClasses { get; set; }
}
...the name of the created join table changes to AClassBClasses and the order of the key columns in the table changes as well. So, the name of the join table and the order of the key columns seems to depend on the order in which the entity classes are "loaded" into the model - which can be the order of the DbSet declarations or another order if more relationship are involved - for example some other entity refering to AClass.
In the end, it doesn't matter at all, because such a many-to-many relationship is "symmetric". If you want to have your own name of the join table, you can specify it in Fluent API as you already did.
So, to your question: Yes, naming the join table AuthorProjects is correct behaviour. If the name had been ProjectAuthors it would be correct behaviour as well though.

EF Code First Many to many relation store additional data in link table

How do I store additional fields in the "link table" that is automagically created for me if I have two entities associated as having a many to many relationship?
I have tried going the "two 1 to many associations"-route, but I'm having a hard time with correctly configuring the cascading deletion.
Unless those extra columns are used by some functions or procedures at the database level, the extra columns in the link table will be useless since they are completely invisible at the Entity Framework level.
It sounds like you need to re-think your object model. If you absolutely need those columns, you can always add them later manually.
You will most likely need to expose the association in your domain model.
As an example, I needed to store an index (display order) against items in an many-to-many relationship (Project <> Images).
Here's the association class:
public class ProjectImage : Entity
{
public Guid ProjectId { get; set; }
public Guid ImageId { get; set; }
public virtual int DisplayIndex { get; set; }
public virtual Project Project { get; set; }
public virtual Image Image { get; set; }
}
Here's the mapping:
public class ProjectImageMap : EntityTypeConfiguration<ProjectImage>
{
public ProjectImageMap()
{
ToTable("ProjectImages");
HasKey(pi => pi.Id);
HasRequired(pi => pi.Project);
HasRequired(pi => pi.Image);
}
}
From Project Map:
HasMany(p => p.ProjectImages).WithRequired(pi => pi.Project);
Maps to the following property on project:
public virtual IList<ProjectImage> ProjectImages { get; set; }
Hope that helps
Ben
Suppose there is a many-to-many association between two types: User and Message, and the association class is defined as UserMessageLink with additional properties.
public class User {
public int Id {get;set;}
}
public class Message {
public int Id {get;set;}
}
//The many-to-many association class with additional properties
public class UserMessageLink {
[Key]
[Column("RecieverId", Order = 0)]
[ForeignKey("Reciever")]
public virtual int RecieverId { get; set; }
[Key]
[Column("MessageId", Order = 1)]
[ForeignKey("Message")]
public virtual int MessageId { get; set; }
public virtual User Reciever { get; set; }
public virtual Message Message { get; set; }
//This is an additional property
public bool IsRead { get; set; }
}

Categories

Resources