What's wrong with this mapping? - entity-framework-4

I want to create following table based on below class dictionary. I get exception when I add records. What's wrong with this mapping? This code works if I point Child property of class "B" to another class (example "C").
database table
table A {id, name}
table B {parentId, childId, Type}
Class and Mapping
Public class A
{
public int Id {get;set;}
public string Description {get;set;}
}
Public class B
{
[Key, Column(Order=0)]
public int ParentId {get;set;}
[Foreignkey("ParentId")]
public A Parent {get;set;}
[Key, Column(Order=1)]
public int ChildId {get;set;}
[Foreignkey("ChildId")]
public A Child {get;set;}
[Key, Column(Order=2)]
public string Type {get;set;}
}
UPDATE
Error Message is: Introducing FOREIGN KEY constraint 'B_Parent' on table 'B' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
Thanks,
Ashraf

After reading the following posts I found the solution.
http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx
Entity Framework Code First - Defining Relationships/Keys
It's the SQL Server error. Class 'A' referencing twice in class 'B'. Code First attempt to turn on cascade delete for both Parent and Child columns in class 'B' which cause the exception.
Fix is manually override one of the cascade option to false in class B. I don't know how to set CascadeOnDelete option as dictionary attribute. But here is the fluent api.
HasRequired(x => x.Parent)
.WithMany()
.HasForeignKey(x => x.ParentId)
.WillCascadeOnDelete(false);
I wish EF team attempt to write a comprehensive guide for Code First configuration (Fluent API) manual for us. AdventureWorks-2008 database is a great candidate for that.

this exception is SQL server specific.It will go away if you turn off the cascade for the relationship.By default Ef will turn it on for you.you can do this through fluent api.
In the relationship just add the following configuration
.WillCascadeOnDelete(false);
hope this helps.

Related

Entity Framework Mapping. Multiple Foreign keys

I have two tables
People Relation
------------- -----------------
Id (int) Id (int)
Name (string) ParentPeopleId (int)
ChildPeopleId (int)
I need to get all people by Relation table with union all.
The relation table has two foreign keys. And there is one problem with mapping them. The mapping is one to many. People has many Relation, Relation has one People.
I mapped them like this:
HasRequired(r=> r.People).WithMany(p=>p.Relation).HasForeignKey(r=>r.ChildPeopleId);
So, how can I map the second foreign key?
Per each FK column in your Relations table you should have a navigation property in your Relation entity (this is not mandatory, but what is mandatory is have at least one navigation property between the entities involve in the relationship). In this case you have two relationships between People and Relations, and a navigation property represents one end in an relationship. Your model could be this way:
public class Relation
{
public int Id {get;set;}
public int ParentPeopleId {get;set;}
public int ChildPeopleId {get;set;}
public virtual People ParentPeople {get;set;}
public virtual People ChildPeople {get;set;}
}
public class People
{
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<Relation> ParentRelations {get;set;}
public virtual ICollection<Relation> ChildRelations {get;set;}
}
And the Fluent Api configurations like this:
HasRequired(r=> r.ParentPeople ).WithMany(p=>p.ParentRelations ).HasForeignKey(r=>r.ParentPeopleId);
HasRequired(r=> r.ChildPeople).WithMany(p=>p.ChildRelations ).HasForeignKey(r=>r.ChildPeopleId );
Now if you don't want to work with one of the collection navigation properties in your People entity, you can create an unidirectional relationship. For example if you don't want ParenRelations navigation property, you can configure that relationship as follow:
HasRequired(r=> r.ParentPeople).WithMany().HasForeignKey(r=>r.ParentPeopleId);
Update
Let me start first with a suggestion. I thing your table Relation is not playing any role is you have only those columns. If a person con only have a parent I would change your model to the following:
public class People
{
public int Id {get;set;}
public string Name {get;set;}
public int ParentId {get;set;}
public virtual People Parent {get;set;}
public virtual ICollection<People> Children {get;set;}
}
And you relationship configuration would be:
HasOptional(r=> r.Parent).WithMany(p=>p.Children).HasForeignKey(r=>r.ParentId);
Now going back to your current model, EF sees your ChildPeopleId property as an simple scalar column, it doesn't know it's a FK column, that's way I suggested above map two relationship instead one.
Another thing, with the below line
var Peoplelist = MyDbContext.People.Include(p=>p.Relations.Select(r=>r.People)).ToList();
You are telling to EF that you want to load the Relation entities related to a People, but also you want to load the People related with each Relation, which is at the same time the same People where the Relation came from, so, you don't need to do the last select, if your data is properly related, that People navigation property is going to be loaded when you execute your query,so, that query should be this way:
var Peoplelist = MyDbContext.People.Include(p=>p.Relations).ToList();

"Cycle or Multiple Cascade Paths" in relationship with the "ApplicationUser" Model

I am defining a lot of classes in my project and as an audit requirement, every entity in my project has to have to foreign keys to the "AspNetUser" table, one specifying the user that created the record, and one for the user that has updated it. The following is a sample of "Customer" entity, however, as I said there is tons of entities all with the same requirement:
public class Customer {
public int Id {get; set;}
// bunch of properties
[Required]
public string CreateUserId {get; set;}
[Required]
public string UpdateUserId {get; set;}
[ForeignKey("CreateUserId")]
public virtual ApplicationUser CreateUser {get; set;}
[ForeignKey("UpdateUserId")]
public virtual ApplicationUser UpdateUser {get; set;}
}
Now because there is two foreign keys to the AspNetUser table, when I want to create migration and update the database I get the good old error:
Introducing FOREIGN KEY constraint 'FK_dbo.Customers_dbo.AspNetUsers_UpdateUserId' on table 'Customers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
I also understand that by adding some codes to the "OnModelCreate" and remove the cascade effect for the "Customer" entity, I will be able to get around this, however, as I said, every entity in my application is going to have this two links to the AspNetUser table which means I have to add that piece of code to the OnModelCreate tons of times each time with the specific entity I'm talking about.
Also, I don't want to cancel the CASCADE DELETE effect as a whole, as it affects the functionality of the app in all of the parts. Any idea how can I efficiently get around this?
I remember back in the days when I did database programming, there was never any issues with one entity having two foreign keys to another one.
you should set WillCascadeOnDelete = False by fluentApi, Like This :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer >()
.HasRequired(c => c.CreateUser)
//.WithMany()
.HasForeignKey(c => c.CreateUserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Customer>()
.HasRequired(c => c.UpdateUser )
//.WithMany()
.HasForeignKey(c => c.UpdateUserId )
.WillCascadeOnDelete(false);
}

Entity Framework Code First : One-To-One association using Annotations

I am having .NET MVC 5 and Identity...
I am trying to get a one to one relationship for my Member class to my MemberInfo class..
So, My classes looks something like this:
IdentityUser is in the Microsoft.AspNet.Identity.EntityFramework namespace with string Id as its ID.
public class GRNUser : IdentityUser {
....
....
}
public class MemberUser : GRNUser {
public virtual Member MemberInfo {get; set; }
}
public class Member {
public int ID {get; set; }
public string MemberUserID {get; set; }
public virtual MemberUser MemberUser { get; set; }
}
In my Context, I have this
modelBuilder.Entity<Member>().HasRequired(m => m.MemberUser)
.WithOptional(u => u.MemberInfo);
So, the MemberUser and Member should be able to navigate to and from each other using the MemberUser's ID property and Member's MemberUserID property.
However, when my Database is created, it has an additional column "MemberUser_Id" instead of using my MemberUserID that I specified. How do I make it use "MemberUserID" that I specified?
I've tried using a few combination so of the ForiegnKey Data Annotation, but keeps on getting this error:
Member_MemberUser_Source: : Multiplicity is not valid in Role 'Member_MemberUser_Source' in relationship 'Member_MemberUser'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
I don't know whether i understood you right or not, but i'l do my best to help.
(I'l assume that you work with code first migration)
If you want to make a one-to-one relation, why not try to make a standalone entity for your info which will have a foreign key for the user entity and that foreign key will be annotated as the primary key of the entity?
Another way is why just not add whatever attributes you like to the Application User entity and work with it?
In any case i might have misunderstood your purpose, so please feel free to explain further since your post is a bit confusing.

Fluent Nhibernate HasMany to One Table from Several Tables

I have an entity/class/table which is referenced from several other entities, and I use Fluent NHibernate to handle the ORM for me. In a few instances, it's a simple reference where I can store the foreign key ID as a column and handle the reference in that simple way, but in a few other instances I need to reference a list of these items, and it needs done for at least three classes I can think of. You can assume this setup will be copied to handle the other classes' relationships.
Here's how the common entity looks (the one that is owned by several other entities in HasManys):
public class Student {
public virtual int Id {get; set;}
public virtual string Name {get; set;}
}
And, here's what the ShopCourse entity looks like:
public class ShopCourse {
public virtual int Id {get; set;}
public virtual int Name {get; set;}
public virtual IList<Student> Students {get; set;}
}
Imagine that a couple other classes I have, such as specific courses, can "own" several students. In order to maintain that relationship I must create a table in my database that tracks the foreign keys between the two (for each entity that references Student) - no entity needed for this intermediate table, and Fluent won't need to think of it unless I hand it the string name of the table itself:
Table: ShopCourseStudents
int - ShopCourseId
int - StudentId
Lastly, here are my mappings. You can assume that the entities themselves map out fine - things such as the naming scheme for the Id are resolved and working correctly. The issue lies when I attempt to initialize any entity that has a HasMany of Student:
//Inside a FluentlyConfigure().Mappings(m => m.AutoMappings.Add() call:
.Override<ShopCourse>(map => {
map.HasMany(x => x.Students)
.Table("ShopCourseStudents")
.KeyColumns.Add("ShopCourseId")
.KeyColumns.Add("StudentId")
.Cascade.All();
})
The issue is that when I attempt to load a list of ShopCourses I get the Fluent error:
Foreign key (ABC123AF9:Student [ShopCourseId, StudentId]) must have
same number of columns as the referenced primary key (ShopCourses
[Id])
I do not override Fluent's mapping of Student as it's straightforward. For the purpose of this example, Student doesn't need to know which ShopCourses it belongs to, or any of the other courses that may own that particular Student record.
This seems like I'm doing something basic, wrong - what is it, exactly? Much obliged in advance!
So, the issue was with the custom code that I re-use with my projects, apparently the piece written to handle the ManyToMany convention is mostly broken. What I was looking for here was a ManyToMany relationship, not HasMany. The issue I had was that my code was forcing a reference on the child object (in this example, Student) to the parent, which I do not need and only complicates things. Removing that, and my ManyToMany then works:
.Override<ShopCourse>(map => {
map.HasManyToMany(x => x.Students)
.Table("ShopCourseStudents")
.ParentKeyColumn("ShopCourseId")
.ChildKeyColumn("StudentId")
.Cascade.All()

Entity Framework: Map Foreign Key without Navigation Property?

Motivation : My EF4.1 DbContext is saving Entities in the wrong order
Reason : Lack of navigation properties on my models
How I want to fix it :
I want to set up foreign key relationships in my DbContext. The catch is that my entity objects have no navigation properties (I'm using it to populate a web service and then firing DTO objects over to my application).
The classes below would be an example. In MinorClass, I want to configure my context so that it knows MajorClassID is a foreign key. The articles I've been finding on the internet on how to explicitly define Foreign Keys involve using navigational properties, which my objects dont have.
Is there a way to map this relationship?
public class MinorClass
{
public Guid ID {get;set:}
public Guid MajorClassID {get;set;} // foreign key
public string Name {get;set;}
}
public class MajorClass
{
public Guid ID {get;set;}
public string Name {get;set;}
}
Navigation property is primary construct whereas foreign key is helper (imho wrong helper). EF recognizes ordering of DB commands by relationships which are defined by navigation properties. You cannot define relation just by foreign key. You need navigation property on at least one side of the relation.

Resources