ef core ignore navigation property - c#

I have an entity User that has two properties CreatedBy and UpdatedBy both referencing User. By default, EF assumes that these two as a one to one relation to each other. I get the following error message:
Message: System.InvalidOperationException : The child/dependent side could not be determined for the one-to-one relationship that was detected between 'User.CreatedBy' and 'User.UpdatedBy'. To identify the child/dependent side of the relationship, configure the foreign key property. If these navigations should not be part of the same relationship configure them without specifying the inverse. See http://go.microsoft.com/fwlink/?LinkId=724062 for more details.
Currently, I have a class like this:
public class User
{
public int Id { get; set; }
public int? CreatedById { get; set; }
public User CreatedBy { get; set; }
public int? UpdatedById { get; set; }
public User UpdatedBy { get; set; }
}
Basically, here is what I am trying:
The created and updated would have no relation to each other (no navigation/inverse property needed)
Any number of users can have the same CreatedBy and any number of users can have the same UpdatedBy.
How can I ask EF to just ignore the navigation property? The main reason I have CreatedBy is so I can use Include(u => u.CreatedBy) later on. I know using IEnumerable<User> AllCreatedUsers property would solve this but I did not want to create an IEnumerable for each in my entity. Is there any way to do this with fluent API?
Here is what I tried:
modelBuilder.Entity<User>()
.Property<IEnumerable<User>>("AllCreatedUsers");
modelBuilder.Entity<User>().HasOne(u => u.CreatedBy)
.WithMany(u => EF.Property<IEnumerable<User>>(u, "AllCreatedUsers"));

You need to configure two Single Navigation Property relationships by using parameterless WithMany method overload:
modelBuilder.Entity<User>()
.HasOne(u => u.CreatedBy)
.WithMany();
modelBuilder.Entity<User>()
.HasOne(u => u.UpdatedBy)
.WithMany();

You ForeignKey data annotation for both the properties.
public class User
{
public int Id { get; set; }
public int? CreatedById { get; set; }
[ForeignKey("CreatedById")]
public User CreatedBy { get; set; }
public int? UpdatedById { get; set; }
[ForeignKey("UpdatedById")]
public User UpdatedBy { get; set; }
}

Related

Cross including the same table relations in EF Code Throws an error Multiplicity constraint violated

I have cross relations with the same table, in 3rd object.
When I try to insert new object, got an error :
Multiplicity constraint violated. The role
'OrgOwners_Organisation_Target' of the relationship
'GBankDataSource.OrgOwners_Organisation' has multiplicity 1 or 0..1.
I've tried to annotate [ForeignKey("...")] in any of the classes, but nothing happend. EF allways choose one field (OrgRefID in this sample) and use it or both relations, while OrgID are not used.
public class OrganisationInfo
{
[Key]
public int OrgID { get; set; }
...
public virtual List<OrgOwners> OrgOwners { get; set; } // object that throws error
}
public class OrgOwners
{
[Key]
public int OrgOwnerID { get; set; }
public int OrgID { get; set; } //Suppose to be a ForeignKey for (OrganisationInfo OrgOwners List)
public int? OrgRefID { get; set; }
...
[ForeignKey("OrgRefID")]
public virtual OrganisationInfo Organisation { get; set; } //(Suppose to use OrgRefID as ForeignKey)
}
When I add a record to OrgOwners without Organisation ( Organisation =null) - it is OK. But when I do
var first = new OrganisationInfo(); //First organisation DB.OrganisationInfoes.Add(first);
var nextOrg = new OrganisationInfo(); //second organisation
first.OrgOwners = new list();
var Owner = new OrgOwners(); Owner.Organsiation = nextOrg;
first.OrgOwners.Add(Owner); // Add Owner with the second organisation to the First one.
I got an error.
Multiplicity constraint violated.
OrgOwner.Organisation - is NOT the same OrganisationInfo as in root of OrgOwners list. It must be different OrganisationInfo items, related to OrgRefID ForeignKey.
It's because EF by default automatically "pairs" the navigation properties where possible to form a relationship. In your case, it pairs OrganizationInfo.OrgOwners collection navigation property with OrgOwners.Organization reference navigation property, hence takes and uses the associated with it OrgRefID FK.
One way to resolve the issue is to add a second reference navigation property to OrgOwners and associate it with the OrgID property via ForeignKey attribute and OrganizationInfo.OrgOwners collection navigation property via InverseProperty attribute:
public int OrgID { get; set; } //Suppose to be a ForeignKey for (OrganisationInfo OrgOwners List)
[ForeignKey("OrgID")]
[InverseProperty("OrgOwners")]
public virtual OrganisationInfo OwnerOrganization { get; set; }
To do that without changing the entity model, you should configure the relationship via fluent API:
modelBuilder.Entity<OrganisationInfo>()
.HasMany(e => e.OrgOwners)
.WithRequired() // no inverse navigation property
.HasForeignKey(e => e.OrgID); // <--
Full worked example:
public class OrganisationInfo
{
[Key]
public int OrgID { get; set; }
public virtual List<OrgOwners> OrgOwners { get; set; }
}
public class OrgOwners
{
[Key]
public int OrgOwnerID { get; set; }
public int OrgID { get; set; }
public int? OrgRefID { get; set; }
[ForeignKey("OrgRefID")]
public virtual OrganisationInfo Organisation { get; set; }
}
modelBuilder.Entity<OrganisationInfo>()
.HasMany(e => e.OrgOwners)
.WithRequired()
.HasForeignKey(e => e.OrgID);

Entity Framework Relationship Error

I get the following error when using Entity Framework:
Unable to determine the principal end of an association between the types
'xxx.Domain.Entities.UserSettings' and 'xxx.Domain.Entities.User'. The
principal end of this association must be explicitly configured using either
the relationship fluent API or data annotations.
Here are the two Entity classes:
public class User
{
[Key, Column("un")]
public string Username { get; set; }
public int Level { get; set; }
public virtual UserSettings UserSettings { get; set; }
}
public class UserSettings
{
[Key]
public string Username { get; set; }
public int ActiveRefresh { get; set; }
[ForeignKey("Username")]
public virtual User User { get; set; }
}
I am not sure how to resolve this error. I am stuck with the database design so I can't update that to fix the issue. Is there a way using Fluent Api to get these associations working?
A User can have a UserSettings object. This is the relationship that is desired.
It looks like you need a one to zero-or-one relationship
// Configure the primary key for the User
modelBuilder.Entity<User>()
.HasKey(t => t.Username);
// Map one-to-zero or one relationship
modelBuilder.Entity<UserSettings>()
.HasRequired(t => t.User)
.WithOptional(t => t.UserSettings);
This is not tested! Remove all the annotations from the entity classes. The link to Fluent API relationships in my comment above has more examples of the different kinds of relationship.
using anotations :
public class User
{
[Key, Column("un")]
public string Username { get; set; }
public int Level { get; set; }
//here is your foreign to UserSettings
public int? UserSettingsID{ get; set; }
[ForeignKey("UserSettingsID")] // not needed if you're using the '%ID' convention
//Navigation property
public virtual UserSettings UserSettings { get; set; }
}
public class UserSettings
{
//UserSettings PK
public int UserSettingsID{ get; set; }
public int ActiveRefresh { get; set; }
}
I assume here that you don't need to retrieve the user from his settings

How to configure zero or one to zero or one relationship with bi-directional navigation with FluentAPI

I'm trying to create a 0..1 to 0..1 relation in entity framework's fluent API. The objective would be to configure the relation navigable from both ends.
The ideia is: One user might be a physician and a physician may or may not have an associated user.
It would be useful to have a bi-directional relation for navigation purposes.
Also, the foreignKey side, on Pysician, should have the ForeignKey property exposed (to set a User ID).
Here's my model and fluentAPI configuration
public class Physician
{
public long Id { get; set; }
public string ProfessionalName { get; set; }
public long? PhysicianUserID { get; set; }
public virtual User PhysicianUser { get; set; }
}
public class User
{
public long Id { get; set; }
public string Email { get; set; }
public virtual Physician UserPhysician { get; set; }
}
modelBuilder.Entity<Physician>()
.HasOptional(A => A.PhysicianUser)
.WithOptionalDependent(A => A.UserPhysician);
modelBuilder.Entity<User>()
.HasOptional(A => A.UserPhysician)
.WithOptionalPrincipal(A => A.PhysicianUser);
The problem is that EF creates a property on Physician called PhysicianUser_ID (instead of using the one I provided). I've tried to add a [ForeignKey()] declaration on the physician entity but that resulted in validations errors.
How can I configure this type of relation ? (If indeed possible)
You need to tell Ef how to map the key
modelBuilder.Entity<User>()
.HasOptional(A => A.UserPhysician)
.WithOptionalPrincipal(A => A.PhysicianUser)
.Map(A => A.MapKey("PhysicianUserID"));

EF mapping one to one optional

I have som mapping problem with EF.
This is my classes
public class User{
public Guid Id { get; set; }
// Fullname of the user account owner
public string Name { get; set; }
public string Email { get; set; }
public string Username { get; set; }
public Player Player { get; set; }
}
public class Player
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual User User { get; set; }
}
It works fine, but now I want to create the navigation property Player and User in this classes. I have this Fluent code:
modelBuilder.Entity<User>()
.HasOptional(x => x.Player)
.WithOptionalDependent(x => x.User)
.Map(x => x.MapKey("Username"));
But I only get this error message, and I have no ide what's wrong.
Each property name in a type must be unique. Property name 'Username'
was already defined.
My DB setup looks like the classes, in the player table the Name is unique. It's not unique in the User table. A user can exist without a player and vice versa. (Actully I don't want any User property inside the Player class but I think it's a requierment?!)
I think it's complaining about the fact that UserName is already a property in the object model. See the docs for the Map() method:
From http://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.configuration.foreignkeynavigationpropertyconfiguration.map%28v=vs.103%29:
Configures the relationship to use foreign key property(s) that are
not exposed in the object model. The column(s) and table can be
customized by specifying a configuration action. If an empty
configuration action is specified then column name(s) will be
generated by convention. If foreign key properties are exposed in the
object model then use the HasForeignKey method. Not all relationships
support exposing foreign key properties in the object model.
Remove the modelBuilder code and mark the PrimaryKey as a ForeignKey on the dependent table. For example if Players don't exist without a User:
public class User
{
public Guid Id { get; set; }
// Fullname of the user account owner
public string Name { get; set; }
public string Email { get; set; }
public string Username { get; set; }
public Player Player { get; set; }
}
public class Player
{
[ForeignKey("User")]
public Guid Id { get; set; }
public string Name { get; set; }
public virtual User User { get; set; }
}
The ForeignKey attribute tells EF which side of the one-to-one is dependent, allowing it to map it properly.
If your columns in the database has the same name as the properties of your model you don't need to map the property ".Map(x => x.MapKey("Username"));" EF already mapped the property "Username" using the convention and is because of that the EF is complaining
With your entities
...I just like to do it the other way around:
modelBuilder.Entity<Player>()
.HasRequired(i => i.User)
.WithRequiredDependent(i => i.Player);
or this (optional):
modelBuilder.Entity<Player>()
.HasRequired(i => i.User)
.WithOptional(x => x.Player);

EF 4.1 Bidirectional one-to-one problem

Hi I am having a problem with a simple EF 4.1 code first model.
I have a class person and a class survey that are bidirectionally linked. The database model is correct but I always get this error:
Unable to determine the principal end of an association between the types 'DAL.Models.Survey' and 'DAL.Models.Person'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Class Person
[Key]
public Guid Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public virtual Survey Survey { get; set; }
Class Survey
[Key]
public Guid Id { get; set; }
public bool IsFinished { get; set; }
public virtual Person Person { get; set; }
Datacontext:
modelBuilder.Entity<Survey>().HasRequired(s => s.Person).WithOptional().WillCascadeOnDelete(true);
Can anyone help please
You should define the other navigation property in your mapping since you have it in the model. Otherwise EF will create a second (one-to-many) association:
modelBuilder.Entity<Survey>()
.HasRequired(s => s.Person)
.WithOptional(p => p.Survey)
.WillCascadeOnDelete(true);
I think you have to specify either a foreign key property through HasForeignKey or foreign key column name using Map. Something like this:
modelBuilder.Entity<Survey>()
.HasRequired(s => s.Person)
.WithOptional()
.WillCascadeOnDelete(true)
.Map(m => m.MapKey("fk_column"));

Categories