Entity Framework - One-way one-to-one relation - entity-framework

I need to make a one-to-one relation between two tables, but only one-way.
[Accounts]
account_id
name
etc...
[SalesReps]
sales_rep_id
account_id
account
etc...
So, I want the SalesReps table to have a relation to Accounts, but I don't want Accounts to have a reference to SalesReps.
I tried this:
modelBuilder.Entity<sales_rep>()
.HasRequired(a => a.account)
.WithMany()
.HasForeignKey(a => a.account_id);
But that gives me:
sales_rep_account_Source: : Multiplicity is not valid in Role 'sales_rep_account_Source' in relationship 'sales_rep_account'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.

The way you do this is with WithRequiredDependent() configuration. Your entities will be:
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SalesRep
{
public int Id { get; set; }
public Account Account { get; set; }
}
In OnModelCreating() method you should do this:
modelBuilder.Entity<Account>().HasKey(x => x.Id);
modelBuilder.Entity<SalesRep>().HasKey(x => x.Id);
modelBuilder.Entity<SalesRep>().HasRequired(x => x.Account).WithRequiredDependent().Map(x => x.MapKey("AccountId"));

It turns out, that all I had to do was:
modelBuilder.Entity<sales_rep>()
.HasRequired(a => a.account)
.WithOptional();

Related

How to change ASP.NET Boilerplate Role entity Id from int to long

I need to add a new party entity (table). This entity follows party design pattern where user, organization unit and role entity Id is primary key and also a foreign key that links to the party entity primary key. I was able to achieve this with user entity and organization entity but not role entity because the role Id is int.
EF core complaints the role table's primary key type mismatched with the party table primary key.
Below are the code samples:
[Serializable]
[Table("MdParties")]
public class Party : FullAuditedEntity<long>, IMayHaveTenant
{
public int? TenantId { get; set; }
}
public partial class User
{
[Required, ForeignKey(nameof(Party))]
public override long Id { get; set; } // PK and FK pointing to Party
public virtual Party Party { get; set; }
}
public class OrganizationUnitExt : OrganizationUnit
{
[Required, ForeignKey(nameof(Party))]
public override long Id { get; set; } // PK and FK pointing to Party
public virtual Party Party { get; set; }
}
public partial class Role : AbpRole<User>
{
[Required, ForeignKey(nameof(Party))]
public override int Id { get; set; } // PK and FK pointing to Party
public virtual Party Party { get; set; }
}
modelBuilder.Entity<User>(b =>
{
b.HasIndex(e => new { e.UserName });
b.HasOne(d => d.Party)
.WithMany()
.HasForeignKey(d => d.Id)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_AbpUsers_PartyId");
});
modelBuilder.Entity<OrganizationUnitExt>(entity =>
{
entity.HasOne(d => d.Party)
.WithMany()
.HasForeignKey(d => d.Id)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_AbpOrganizationUnits_PartyId");
});
You cannot change RoleId type without rebuilding standard Abp package. This is how it was design unfortunetly. However you can walkaround this and add additional table with RoleId and in modelbuilder make it table as Unique Tenant Wise. This will be not trully SQL strict implementation cause you will get one-to-many relation but behaviour of it will be as you expect.

Entity Framework - Fluent API 1 to 0.1 Moderator / Person

I am receiving this error in my migrations:
Person_EventModerator_Target: : Multiplicity is not valid in Role 'Person_EventModerator_Target' in relationship 'Person_EventModerator'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
Here are my models (note: base entity holds the primary key for all models):
public class EventModerator : BaseEntity
{
......
// foreign keys
public int PersonId { get; set; }
// associations
[ForeignKey("PersonId")]
public Person Person { get; set; }
}
public class Person : BaseEntity
{
public Person()
{
....
// association
public virtual EventModerator EventModerator { get; set; }
}
My Mappings:
modelBuilder.Entity<Person>()
.HasOptional(e => e.EventModerator)
.WithRequired(e => e.Person);
This is a 1 to 0.1 relationship.
Can anyone point out my error please?
OK, this worked, but frankly I do not understand the need for ".WithMany()"
internal static void Map(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<EventModerator>()
.HasRequired(e => e.Person)
.WithMany()
.HasForeignKey(e => e.PersonId)
.WillCascadeOnDelete(false);
}
Your answer will not produce 1 to 0.1 relationship. There is another key generated on Person table in the database, that is nullable EventModerator_Id.
To have 1 to 0.1, the dependent EventModerator primary key must also be the foreign key.
You can either add [Key] attribute on PersonId.
[Key]
public int PersonId { get; set; }
Or since you have BaseEntity which might have derived Id property (which by default convention is a primary key), then you just need to remove the PersonId property and link foreign key to Id property.
//public int PersonId { get; set; }
// associations
[ForeignKey("Id")]
public Person Person { get; set; }

Why is this column getting generated in EF Code-First migrations?

I have a Mentorship entity, which has Student and Mentor as FKs:
[Required]
public int MentorId { get; set; }
public virtual User Mentor { get; set; }
[Required]
public int StudentId { get; set; }
public virtual User Student { get; set; }
User model:
public virtual ICollection<Mentorship> Mentorships { get; set; }
Fluent API:
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Mentor)
.WithMany()
.HasForeignKey(u => u.MentorId);
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Student)
.WithMany()
.HasForeignKey(u => u.StudentId);
In my database, I see StudentId and MentorId columns which have been populated correctly, but I also see a User_UserId column that is not being used by anything. What have I done wrong?
You have used the WithMany() overload that configures the relationship to be required:many without a navigation property on the other side of the relationship - but you do have a navigation property on the other side of the relationship.
Try this:
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Mentor)
.WithMany(d => d.Mentorships)
.HasForeignKey(u => u.MentorId);
modelBuilder.Entity<Mentorship>()
.HasRequired(c => c.Student)
.WithMany(d => d.Mentorships)
.HasForeignKey(u => u.StudentId);//oops! just realised that we just
//specified that Mentorships is using MentorId
//as the FK
References:
Required WithMany Method
Why do I get an extra foreign key?
Edit
Scratch that. Just realised you are trying to create two relationships with only one navigation property on the many side. You can't have a navigation property with 2 foreign keys. You need to introduce inheritance on the User side or remove the Mentorships navigation property from the User class or introduce separate StudentMentorships and MentorMentorships navigation properties
Edit 2
Finding a user once you've defined separate navigation properties
int userId = 123;//the one we want to find
var user = Users.Where(x => x.StudentMentorships.Any(s => s.StudentID == userId)
|| x.MentorMentorships.Any(s => s.MentorID == userId);

EF Code First: Primary Key same as Foreign Key

I have two classes
public class Product
{
public Guid Id { get; set; }
public string ProductDetails { get; set; }
}
public class SpecialProductDetails
{
public Guid Product_Id { get; set; } // PK and FK to Product class
public string SpecialName { get; set; }
public string SpecialDescription { get; set; }
public virtual Product Product { get; set; }
}
SpecialProductDetails is mapped 1-1 with Product class and is optional. It shares the same PrimaryKey and ForeignKey.
In Fluent API i am mapping this relationship like this (inside SpecialProductDetails)
public SpecialProductDetails()
{
HasKey(p => p.Product_Id);
HasRequired(p => p.Product).WithMany().HasForeignKey(p => p.Product_Id).WillCascadeDelete(true);
}
This gives me this error when trying to generate the Database
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'SpecialProductDetails_Product_Source' in relationship 'SpecialProductDetails_Product_Source'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
How can i have a column set as PK and FK on EF Code First?
I'm quite sure you have already solved that, but I hit the same problem and the solution I found was:
public SpecialProductDetails()
{
HasKey(p => p.Product_Id);
HasRequired(p => p.Product).WithOptional();
}
"it worth noting that when we are mapping a one-to-one association with fluent API, we don't need to specify the foreign key as we would do when mapping a one-to-many association with HasForeignKey method. Since EF only supports one-to-one associations on primary keys, it will automatically create the relationship in the database on the primary keys."
after http://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-3-shared-primary-key-associations

Mapping entities with fluent api on entity framework 5

I have a question.
I have these two tables:
The principal table is User with Customer dependence.
The reverse engineer code first generated classes as follows:
public class User
{
public User()
{
this.Customers = new List<Customer>();
}
...
public virtual ICollection<Customer> Customers { get; set; }
}
public class Customer
{
public Customer()
{
}
...
public int UserID { get; set; }
public virtual User User { get; set; }
}
I made the following modification in the user class:
public class User
{
public User()
{
}
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
Because the relationship is One-to–Zero-or-One.
The original mapping is this:
// Relationships
this.HasRequired(t => t.User)
.WithMany(t => t.Customers)
.HasForeignKey(d => d.UserID);
And the modified mapping is this :
this.HasRequired(t => t.User)
.WithOptional(t => t.Customer)
.Map(m => m.MapKey("UserID"));
Is That correct?
If not, how would this mapping?
Thanks.
No, it's not correct.
The best thing you can do - supposed you can change the database schema - is removing the UserID foreign key from the Customer table and then create the relationship in the database between the two primary keys so that Customer.CustomerID is the foreign key in the association.
Reverse Engineering should then automatically create the expected one-to-one relationship, like so:
public class Customer
{
public int CustomerID { get; set; }
public virtual User User { get; set; }
//...
}
public class User
{
public int UserID { get; set; }
public virtual Customer Customer { get; set; }
//...
}
//...
this.HasRequired(t => t.User)
.WithOptional(t => t.Customer);
If you can't change the database schema, your best bet is to only remove the collection ICollection<Customer> Customers from the User class and keep the relationship as one-to-many.
The reason for all this is that EF only supports shared primary key one-to-one associations, but not foreign key one-to-one associations. (The latter one you can only "fake" by removing the collection, but it's still one-to-many from EF viewpoint.)
You can read more about one-to-one associations with EF and its limitations here:
One-to-one Shared Primary Key Associations
One-to-one Foreign Key Associations