Entity Framework - Fluent API 1 to 0.1 Moderator / Person - entity-framework

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; }

Related

Could a foreign key property be a part of a composite primary key?

Following the TPC pattern.
I've one abstract class called Entity which is inherited by Person and LegalEntity.
public abstract class Entity
{
public int Id { get; set; }
}
public class LegalEntity : Entity
{
public string CorporateName { get; set;}
}
public class Person : Entity
{
public string Name { get; set; }
}
I've also another one called Agent which have many children. For simplification i'll show only one class Subscriber.
public abstract class Agent
{
public int EntityId { get; set; }
public int RoleId { get; set; }
}
public class Subscriber : Agent
{
public string Number { get; set; }
public Entity Entity { get; set; } // No EntityId here because the foreign key correspond to the Id of Subscriber
}
Below the configuration of my entities :
public AgentConfiguration()
{
HasKey(s => new { s.EntityId, s.RoleId });
...
}
public SubsbcriberConfiguration()
{
Map(m =>
{
m.MapInheritedProperties();
m.ToTable("T_ACTEUR_SOUSCRIPTEUR");
}
**.WithMany() //I don't want a property on the other side
.HasForeignKey(s => s.EntityId); // EF doesn't accept to put the property Id as a foreign key.**
}
public EntityConfiguration()
{
HasKey(e => e.Id);
Property(e => e.Id).HasColumnName("id_personne");
...
}
public PersonConfiguration()
{
Map(m =>
{
m.MapInheritedProperties();
m.ToTable("T_PERSONNE_PHYSIQUE");
});
}
I have a One to One relationship between the abstract class Entity and the concrete class Subscriber.
The primary key of the class Entity is at the same time a part of the composite primary key of the Subscriber and a foreign key.
Is it possible to configure this scenario?
When i declare the property Id as a foreign key, EF throws an exception like below :
The foreign key component 'EntityId' is not a declared property on type 'Subscriber'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.
I tried many scenarios, but i didn't find a solution because i have a one to one relationship but the tables have different keys and the foreign key is a part of the composite primary key.
How can i configure a property as a foreign key and also a part of a composite primary key in code first?
What am I missing? Any help will be greatly appreciated!
Edit :
I broke up the inheritance of the class Agent and the TPC. Now the class Subscriber has no parent. when i configure it like below :
public SubsbcriberConfiguration()
{
HasKey(s => new { s.EntityId, s.RoleId });
Property(s => s.EntityId).HasColumnName("id_personne")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(s => s.RoleId).HasColumnName("id_role")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
...
ToTable("T_ACTEUR_SOUSCRIPTEUR");
HasRequired(s => s.Entity)
.WithMany()
.HasForeignKey(s => s.EntityId)
.WillCascadeOnDelete(false);
}
Entity Framework is looking for another foreign key : column Extent1.Entity_Id does not exist
And the query generated by EF when i try to load a subscriber is :
`SELECT
"Extent1"."id_personne",
"Extent1"."id_role",
...
"Extent1"."Entity_Id"
FROM "T_ACTEUR_SOUSCRIPTEUR" AS "Extent1"
WHERE "Extent1"."id_personne" = ((73660)) AND
"Extent1"."id_role" = ((4))`
I don't know how to explain to EF that the foreign key property EntityId is the foreign key.
Could someone shed some light on this?
Thanks.
Well, I'm not sure if I understand your scenario, but this might be helpful.
Entities:
public class Entity
{
public int EntityId { get; set; }
}
public abstract class Agent
{
public int EntityId { get; set; }
public int RoleId { get; set; }
}
public class Subscriber : Agent
{
public string Number { get; set; }
public Entity Entity { get; set; }
}
Mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity>()
.HasKey(e => e.EntityId);
//map the Subscriber, not the Agent
modelBuilder.Entity<Subscriber>()
.HasKey(a => new { a.EntityId, a.RoleId });
modelBuilder.Entity<Subscriber>()
.HasRequired(i => i.Entity)
.WithMany()
.HasForeignKey(i => i.EntityId)
.WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
Be aware that it is an "One-to-Many" relationship, not One-to-One. The article you posted on your comment uses UNIQUE CONSTRAINTS to "simulate" the 1:1 relationship in a 1:n relationship. I don't think it is a good approach.
However, let's suppose that you want to follow that way. Where would you put the UNIQUE CONSTRAINT? The FK is part of the composite PK. If you put an UNIQUE CONSTRAINT there, it would break the PK.
Considering that the PK is composed by two columns, and the FK is composed by 1 column of the PK, I don't see how a real 1:1 relationship can be possible. Because to have a 1:1 relationship, the FK column must be the same of PK column.
Hope it helps!

How to configure one to one relation using only fluent api without conventions

Is it possible to configure one to one relationship using fluent api on database which does not meet convention requirements?
Below I give you sample of database and generated models.
Be aware of that tables do not define any constraints and indices except primary keys.
Tables:
create table Person (
PersonKey int primary key
)
create table Address (
AddressKey int primary key,
owner int not null // normally should be foreign key to Person
)
Code first models generated from db:
public partial class Person
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int PersonKey { get; set; }
}
public partial class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int AddressKey { get; set; }
public int Owner { get; set; }
}
To be able to navigate from Address to Person, navigation property was added to Address class:
public partial class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int AddressKey { get; set; }
public int Owner { get; set; }
public virtual Person Person { get; set; }
}
If program tries execute this query:
var Addresss = context.Addresss.Include(x => x.Person).ToList();
runtime raises exception: "Invalid column name 'Person_PersonKey'". Because context do not configure any custom mappings it tries to find foreign key by convention but Owner property does not meet convention requirements, hence the exception. So there is a need to add mappings.
If relationship between Person and Address would be one to many we could add such a configuration:
modelBuilder.Entity<Address>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.Owner);
and query defined above would execute correctly. But what if Person class would have navigation property to Address so we would have bidirectional one to one relation:
public partial class Person
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int PersonKey { get; set; }
public virtual Address Address { get; set; }
}
So above configuration will not work and my question is, is it possible to configure it without changing db and property names and if yes what configuration needs to be applied using only fluent api?
Here is my suggested code, I hope I understand you correctly!
public partial class Person
{
public int PersonKey { get; set; }
public Address Address {get;set;}
}
public partial class Address
{
public virtual Person Person { get; set; }
public int PersonId { get; set; }
public string AddressInfo {get;set;}
}
modelBuilder.Entity<Person>()
.HasKey(a => a.PersonKey);
modelBuilder.Entity<Course>()
.Property(c => c.CourseId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<Address>()
.HasKey(a => a.PersonId);
modelBuilder.Entity<Person>()
.HasRequired(p => p.Address)
.WithRequiredPrincipal(a => a.PersonId);

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

Entity framework 5 foreign key mapping convention

I have 2 entities Role and Permission with association one-to-many accordingly.
public class Role
{
public int Id { get; set; }
public bool IsAdmin { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
}
public class Permission
{
public int Id { get; set; }
public string Code { get; set; }
public string GroupName { get; set; }
public virtual Role Role { get; set; }
}
And created mapping classes for them inherited from EntityTypeConfiguration class.
When I run my application EF created database for me and foreign key for these entities above was Role_Id.
How can I change existing or add new convention to get ride of the underscore in foreign key?
So I want to have RoleId as a foreign key for my entities.
I don't want use data annotation attributes and don't want to add extra property to Permission class (public int RoleId { get; set; }) in order to use it in mapping like this:
HasRequired(x => x.Role).WithMany(y => y.Permissions).HasForeignKey(o => o.RoleId);
Thanks,
Alexey
Entity framework currently doesn't support custom global conventions but you can overwrite the name of the key in fluen API:
modelBuilder.Entity<Permission>()
.HasRequired(x => x.Role)
.WithMany(y => y.Permissions)
.Map(m => m.MapKey("RoleId"));