One to many relationship error - entity-framework

I have the following model, but I keep getting an error:
Unhandled Exception: System.InvalidOperationException: A relationship
multiplici ty constraint violation occurred: An EntityReference can
have no more than one r elated object, but the query returned more
than one related object. This is a no n-recoverable error.
public class Tournament
{
public long TournamentId { get; set; }
public string Title { get; set; }
public virtual User CreatedBy { get; set; }
}
public class User
{
public int UserId { get; set; }
}
modelBuilder.Entity<Tournament>()
.HasRequired(t => t.CreatedBy)
.WithOptional()
.Map(c => c.MapKey("CreatedById")); // correct column name

Your model fluent configuration entry is incorrect. Change it as follows
modelBuilder.Entity<Tournament>()
.HasRequired(t => t.CreatedBy)
.WithMany()
.Map(c => c.MapKey("CreatedById")); // correct column name

You'll have better luck managing Foreign keys if you modify you model a bit:
public class Tournament
{
public long TournamentId { get; set; }
public string Title { get; set; }
public virtual int CreatedById {get;set;}
public virtual User CreatedBy { get; set; }
}
and your mapping would look more like this:
modelBuilder.Entity<Tournament>()
.HasRequired(t => t.CreatedBy)
.WithMany()
.HasForeignKey(t => t.CreatedById); // correct column name
This way, when you create a new Tournament Entity you need only pass in the CreatedById and not the entire User object.

This can also happen if you have lazy loading enabled and not specifying all the navigation properties as Overridable (C# Virtual).

Related

EF Core wrong Join entity type name

I have three entities as shown here:
public class Application
{
[Key]
public int ApplicationId { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<Application> Applications { get; set; }
}
Join entity
public class UserApplication
{
public int UserId { get; set; }
public int ApplicationId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
[ForeignKey("ApplicationId")]
public Application Application { get; set; }
}
OnModelCreating section =>
modelBuilder.Entity<User>()
.HasMany(x => x.Applications)
.WithMany(x => x.Users)
.UsingEntity(ua => ua.ToTable("UserApplication"));
modelBuilder.Entity<UserApplication>()
.HasKey(a=> new { a.ApplicationId, a.UserId});
Running the code is causing an error
invalid object name => ApplicationUser.
Note - while OnModelCreating only entity with wrong name is there. DB Has table with name UserApplication
You are using mixture of explicit and implicit join entity. I'm afraid EF Core assumes 2 separate many-to-many relationships with 2 separate tables. Note that by convention the implicit join entity name is {Name1}{Name2} with names being in ascending order, which in your case is ApplicationUser.
What you need is to use the the generic overload of UsingEntity fluent API and pass the explicit join entity type as generic type argument. Also configure the join entity there instead of separately. e.g.
modelBuilder.Entity<User>()
.HasMany(x => x.Applications)
.WithMany(x => x.Users)
.UsingEntity<UserApplication>(
// ^^^
ua => ua.HasOne(e => e.Application).WithMany().HasForeignKey(e => e.ApplicationId),
ua => ua.HasOne(e => e.User).WithMany().HasForeignKey(e => e.UserId),
ua =>
{
ua.ToTable("UserApplication");
ua.HasKey(a => new { a.ApplicationId, a.UserId });
});

EF Core - One to many relationship with additional navigation property of same dependent entity type

I'm having trouble configurating my relationships in EF Core. I've been greeted with the following exception -
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other
FOREIGN KEY constraints
I've trimmed back the entities for this post, but both of these entities have their own table.
public class ApplicationSetupTest
{
public Guid Id { get; set; }
public Guid SchemeId { get; set; }
public string Description { get; set; }
public Guid LatestVersionId { get; set; }
public ApplicationSetupVersionTest LatestVersion { get; set; }
public ICollection<ApplicationSetupVersionTest> VersionHistory { get; set; }
}
public class ApplicationSetupVersionTest
{
public Guid Id { get; set; }
public Guid SetupId { get; set; }
public string Data { get; set; }
public string AuditComment { get; set; }
public Guid PreviousVersionId { get; set; }
}
The ApplicationSetupTest class effectively defines static data with a LatestVersionId that is the key for navigation property LatestVersion.
The ApplicationSetupVersionTest class is the versioned/audited data. Each one of these has a SetupId to link it back to the ApplicationSetupTest to which is refers.
I added the VersionHistory property purely for this post to demonstrate that there could be multiple ApplicationSetupVersionTest on every ApplicationSetupTest. I haven't added an ApplicationSetupTest on the ApplicationSetupVersionTest as this isn't something I expect to need.
My configuration for ApplicationSetupTest is then as follows:
public class ApplicationSetupEntityConfiguration : IEntityTypeConfiguration<ApplicationSetupTest>
{
public void Configure(EntityTypeBuilder<ApplicationSetupTest> builder)
{
builder.Property(t => t.SchemeId).IsRequired();
builder.Property(t => t.Description).IsRequired();
builder.Property(t => t.LatestVersionId).IsRequired();
builder.HasMany(t => t.VersionHistory)
.WithOne()
.HasForeignKey(t => t.SetupId)
.IsRequired();
builder.HasOne(t => t.LatestVersion)
.WithOne()
.HasForeignKey<ApplicationSetupTest>(t => t.LatestVersionId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired();
builder.HasOne<Scheme>()
.WithMany()
.HasForeignKey(t => t.SchemeId)
.IsRequired();
}
}
The HasMany -> WithOne on VersionHistory is there to define that when I delete a setup, I should delete all version entities.
I assume the second configuration is therefore the area to change. The OnDelete(NoAction) was added following Google searches and I also tried removing the IsRequired() as well as making the LatestVersionId nullable.
I am looking to configure the second relationship so that the LatestVersion property can be included on query.
Any thoughts out there on how to configure such a relationship? Or am I doing something that you wouldn't recommend?
(I will refer to the models as Setup and Version for simplicity).
With your one-to-many configuration -
builder.HasMany(t => t.VersionHistory)
.WithOne()
.HasForeignKey(t => t.SetupId)
.IsRequired();
you have declared Setup as the principal end, and Version as the dependent end, which is correct.
But then you have a LatestVersionId foreign key in Setup, referencing to Version, and configuration of the one-to-one relationship -
builder.HasOne(t => t.LatestVersion)
.WithOne()
.HasForeignKey<ApplicationSetupTest>(t => t.LatestVersionId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired();
trying to configure Setup as the dependent end and Version as the principal end. I'm sure you can see the contradiction.
With the following simplified models -
public class Setup
{
public Guid Id { get; set; }
public string Description { get; set; }
public Version LatestVersion { get; set; }
public ICollection<Version> VersionHistory { get; set; }
}
public class Version
{
public Guid Id { get; set; }
public string Data { get; set; }
// not nullable - every Version must belong to a Setup
public Guid SetupIdHistory { get; set; }
// nullable - not every Version is a latest version
public Guid? SetupIdLatest { get; set; }
}
you can configure them correctly to represent your relationships as -
public void Configure(EntityTypeBuilder<Setup> builder)
{
builder.HasMany(p => p.VersionHistory)
.WithOne()
.HasForeignKey(p => p.SetupIdHistory)
.OnDelete(DeleteBehavior.Cascade) // not required, cascading is default
.IsRequired();
builder.HasOne(p => p.LatestVersion)
.WithOne()
.HasForeignKey<Version>(p => p.SetupIdLatest)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
}
If you choose not to have a foreign key for the one-to-many relationship, EF will create a nullable one for you and manage the relationship at model level with a shadow property. But for the one-to-one relationship, you must define a foreign key.
public class Version
{
public Guid Id { get; set; }
public string Data { get; set; }
// nullable - not every Version is a latest version
public Guid? SetupId { get; set; }
}
public void Configure(EntityTypeBuilder<Setup> builder)
{
builder.HasMany(p => p.VersionHistory)
.WithOne()
.OnDelete(DeleteBehavior.Cascade)
.IsRequired(); // this will have no effect, the FK will be nullable
builder.HasOne(p => p.LatestVersion)
.WithOne()
.HasForeignKey<Model.Version>(p => p.SetupId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
}

One to Many with two Properties from the same class

I have the following classes that I would really like to map correctly in EF:
internal class Wallet : EntityFrameworkEntity
{
public Wallet()
{
this.Requests = new List<FinancialRequest>();
}
public string Name { get; set; }
public string Description { get; set; }
public decimal CurrentBalance { get; set; }
public decimal BlockedBalance { get; set; }
public virtual ICollection<Paper> Papers { get; set; }
public virtual ICollection<FinancialRequest> Requests { get; set; }
public virtual User Manager { get; set; }
}
internal class Request : EntityFrameworkEntity
{
public Int64 UserId { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public RequestStatus Status { get; set; }
public virtual User User { get; set; }
}
internal class FinancialRequest : Request
{
public DateTime ValidUntil { get; set; }
public FinancialRequestType RequestType { get; set; }
public int Quantity { get; set; }
public bool UseMarketValue { get; set; }
public decimal? Value { get; set; }
public virtual Wallet Source { get; set; }
public virtual Wallet Destination { get; set; }
public virtual Team Team { get; set; }
}
I'm using Code First, so this is my method that maps those classes:
modelBuilder.Entity<Wallet>()
.HasMany(x => x.Requests)
.WithOptional();
modelBuilder.Entity<Wallet>()
.HasMany(x => x.Papers)
.WithOptional(x => x.Owner)
.Map(configuration => configuration.MapKey("OwnerId"));
modelBuilder.Entity<Wallet>()
.HasMany(x => x.Requests)
.WithOptional();
modelBuilder.Entity<Request>().ToTable("Requests");
modelBuilder.Entity<FinancialRequest>().ToTable("FinancialRequests");
modelBuilder.Entity<FinancialRequest>()
.HasRequired(x => x.Team)
.WithOptional()
.Map(configuration => configuration.MapKey("TeamId"));
modelBuilder.Entity<FinancialRequest>()
.HasOptional(x => x.Destination)
.WithOptionalDependent()
.Map(configuration => configuration.MapKey("DestinationWalletId"));
modelBuilder.Entity<FinancialRequest>()
.HasRequired(x => x.Source)
.WithRequiredDependent()
.Map(configuration => configuration.MapKey("SourceWalletId"));
If I leave this mapping the way it's now, my database schema looks like this:
If you look carefully, you'll see that there's a column called "Wallet_Id" that it's not suposed to be there. This column only exists because the Wallet class has the "Requests" collection.
If I remove the collection from the the columns goes away, but I need this collection! It representes a importante relation between the classes. What I don't need is the 3rd column in the database wrongly generated.
Does anybody knows how can I avoid this? What am I doing wrong here?
The problem that causes the redundant foreign key column Wallet_Id is that EF doesn't know if the Wallet.Requests collection is the inverse navigation property of FinancialRequest.Source or FinancialRequest.Destination. Because it cannot decide between the two EF assumes that Wallet.Requests doesn't have an inverse navigation property at all. The result is a third redundant one-to-many relationship with the third FK.
Basically you have three options:
Remove the Wallet.Requests collection and the third relationship will disappear (as you already have noticed). But you don't want that.
Tell EF explicitly if Wallet.Requests has Source or Destination as inverse navigation property:
// Remove the modelBuilder.Entity<Wallet>().HasMany(x => x.Requests) mapping
modelBuilder.Entity<FinancialRequest>()
.HasOptional(x => x.Destination)
.WithMany(x => x.Requests)
.Map(config => config.MapKey("DestinationWalletId"));
modelBuilder.Entity<FinancialRequest>()
.HasRequired(x => x.Source)
.WithMany()
.Map(config => config.MapKey("SourceWalletId"));
Use WithMany(x => x.Requests) in one of the two (Destination in the example, it could also be Source), but not in both.
Introduce a second collection in Wallet and map the two collections to Source and Destination respectively:
internal class Wallet : EntityFrameworkEntity
{
public Wallet()
{
this.SourceRequests = new List<FinancialRequest>();
this.DestinationRequests = new List<FinancialRequest>();
}
// ...
public virtual ICollection<FinancialRequest> SourceRequests { get; set; }
public virtual ICollection<FinancialRequest> DestinationRequests { get; set; }
}
Mapping:
// Remove the modelBuilder.Entity<Wallet>().HasMany(x => x.Requests) mapping
modelBuilder.Entity<FinancialRequest>()
.HasOptional(x => x.Destination)
.WithMany(x => x.DestinationRequests)
.Map(config => config.MapKey("DestinationWalletId"));
modelBuilder.Entity<FinancialRequest>()
.HasRequired(x => x.Source)
.WithMany(x => x.SourceRequests)
.Map(config => config.MapKey("SourceWalletId"));
BTW: Shouldn't both Source and Destination be required? If yes, you can replace the HasOptional by HasRequired but you must append WillCascadeOnDelete(false) to at least one of the two mappings to avoid a multiple cascading delete path exception.

EF 5.0 Code First Two way navigation withought foreign key id in child

I have following classes
public class Employer
{
[Key]
public Int64 EmployerID { get; set; }
public String CompanyName { get; set; }
public virtual List<Employee> Employees { get; set; }
}
public class Employee
{
[Key]
public Int64 EmployeeID { get; set; }
public String EmployeeName { get; set; }
public virtual Employer EmployerInfo { get; set; }
}
In the Database context I have set the relation as
modelBuilder.Entity<Employer>()
.HasMany(p => p.Employees)
.WithRequired()
.Map(x => x.MapKey("EmployerID"));
After executing some actions, database gets created with Employee table having EmployerID as foreign key and one extra key EmployerInfo_EmployerID.
Now when I fetch employer data, I am getting employee details with it.
But when I tried to fetch employee data I am getting EmployerInfo as null. This is because I need relationship from Employee to EmployerInfo.
How do I set the bi-directional relationship in this context?
You need to update your fluent so your relationship mapping contains both ends:
modelBuilder.Entity<Employer>()
.HasMany(p => p.Employees)
.WithRequired(e => e.EmployerInfo)
.Map(x => x.MapKey("EmployerID"));

Specifying Foreign Key Entity Framework Code First, Fluent Api

I have a question about defining Foreign Key in EF Code First Fluent API.
I have a scenario like this:
Two class Person and Car. In my scenario Car can have assign Person or not (one or zero relationship).
Code:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public Person Person { get; set; }
public int? PPPPP { get; set; }
}
class TestContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Car> Cars { get; set; }
public TestContext(string connectionString) : base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
}
In my sample I want to rename foreign key PersonId to PPPPP. In my mapping I say:
modelBuilder.Entity<Car>()
.HasOptional(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PPPPP)
.WillCascadeOnDelete(true);
But my relationship is one to zero and I'm afraid I do mistake using WithMany method, but EF generate database with proper mappings, and everything works well.
Please say if I'm wrong in my Fluent API code or it's good way to do like now is done.
Thanks for help.
I do not see a problem with the use of fluent API here. If you do not want the collection navigational property(ie: Cars) on the Person class you can use the argument less WithMany method.