Entity Mapping in EF Core 6 - entity-framework-core

I would like to convert the following EF 6 code into EF Core 6.
HasMany(company => company.AssociatedTo)
.WithMany(x => x.AssociatedFrom)
.Map(mc =>
{
mc.MapLeftKey("Company_1");
mc.MapRightKey("Company_2");
mc.ToTable("Companies_Companies");
});
I have tried this, but for some reason, it doesn't pick any values
builder.Entity<Compnay>
.HasMany(company => company.AssociatedTo)
.WithMany(x => x.AssociatedFrom)
.UsingEntity<Companies_Companies>(
j => j
.HasOne<Company>()
.WithMany()
.HasForeignKey(x => x.Company_1),
j => j
.HasOne<Company>()
.WithMany()
.HasForeignKey(x => x.Company_2)
);
These are my Entity Models:
public class Company
{
[Key]
public int Id { get; set; }
...
[NotMapped]
public IEnumerable<Company> AssociatedCompanies => (AssociatedFrom ?? new List<Company>())
.Union(AssociatedTo ?? new List<Company>()).Where(x => x.Id != Id).Distinct().ToArray();
public virtual ICollection<Company> AssociatedFrom { get; set; } = new List<Company>();
public virtual ICollection<Company> AssociatedTo { get; set; } = new List<Company>();
...
}
And the Companies_Companies Model, I added to support Many-to-Many relationship
public class Companies_Companies
{
public int Company_1 { get; set; }
public int Company_2 { get; set; }
}

You can establish many to many relationships like this, my score is not enough to comment, but if you share your entityModel, I can help more.
builder.Entity<Compnay>()
.HasMany(x => x.AssociatedFrom).WithMany(x => x.AssociatedTo)
.UsingEntity<Dictionary<string, object>>("TableNameHere",
x => x.HasOne<Compnay>().WithMany().HasForeignKey("CompnayId").HasConstraintName("CompnayFK"),
x => x.HasOne<AssociatedFromModels>().WithMany().HasForeignKey("AssociatedFromId").HasConstraintName("AssociatedFromFK"));

Related

Can't define composite key in my EF Core database-first ASP.NET Core Web API

I have following model of a table:
public partial class FlightsOfTicket
{
public int TicketId { get; set; }
public int FlightId { get; set; }
public int PlaneId { get; set; }
public int FlightNumber { get; set; }
public bool? IsDirect { get; set; }
public virtual Flight Flight { get; set; }
public virtual Plane Plane { get; set; }
public virtual Ticket Ticket { get; set; }
}
And my DbContext has the following code:
modelBuilder.Entity<FlightsOfTicket>(entity =>
{
entity.HasKey(e => new { e.TicketId, e.FlightId, e.PlaneId });
entity.ToTable("FlightsOfTicket");
entity.Property(e => e.IsDirect)
.IsRequired()
.HasDefaultValueSql("((1))");
entity.HasOne(d => d.Flight)
.WithMany(p => p.FlightsOfTickets)
.HasForeignKey(d => d.FlightId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_FlightsOfTicket_Flight");
entity.HasOne(d => d.Plane)
.WithMany(p => p.FlightsOfTickets)
.HasForeignKey(d => d.PlaneId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_FlightsOfTicket_Plane");
entity.HasOne(d => d.Ticket)
.WithMany(p => p.FlightsOfTickets)
.HasForeignKey(d => d.TicketId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_FlightsOfTicket_Ticket");
});
I know that entity.HasKey(e => new { e.TicketId, e.FlightId, e.PlaneId }) creates a composite key, but at runtime I got this exception:
which means, as far as I know, that it's not creating the composite primary key.
I've tried to create key in different places, tried to re-scaffold model and nothing - it keeps not working for 6 hours now

How to create relationship with temporal table in EF Core

I want to create a 1-0..1 relation between a table and a temporal table using EF Core code-first approach. But when I add the migration I get the error :
Navigation 'Ticket (Dictionary<string, object>).TicketAdministration' was not found. Please add the navigation to the entity type before configuring it.
I let you see step by step what I am doing:
I create the Ticket and TicketAdministration classes:
public partial class Ticket
{
public long Id { get; set; }
//... other unuseful props
public virtual TicketAdministration TicketAdministration { get; set; }
}
public class TicketAdministration
{
public long Id { get; set; }
//... other unuseful props
public long? TicketId { get; set; }
public virtual Ticket Ticket { get; set; }
}
Then I configured the two classes/tables:
modelBuilder.Entity<Ticket>(entity =>
{
entity.ToTable("tickets");
entity.Property(e => e.Id)
.HasColumnType("bigint")
.ValueGeneratedOnAdd();
});
modelBuilder.Entity<TicketAdministration>(entity =>
{
entity.ToTable("ticket_admininistration", "admin", t => t.IsTemporal());
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).UseIdentityColumn(1, 1);
entity.HasOne(d => d.Ticket)
.WithOne(p => p.TicketAdministration)
.HasForeignKey<TicketAdministration>(b => b.TicketId)
.OnDelete(DeleteBehavior.ClientCascade)
.HasConstraintName("FK_dbo.Tickets_admin.TicketAdministration_TicketId");
});
How do I have to configure the relationship? Why is it expecting a dictionary? What the dictionary represent?
Thank you

EF 6.1.3 Multiplicity conflicts

I have been getting error when I try to run add-migration script.
The error is:
Domain.DataAccessLayer.AllRoutines_Product: : Multiplicity conflicts with the referential constraint in Role 'AllRoutines_Product_Target' in relationship 'AllRoutines_Product'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'.
And I cannot figure what I am doing wrong. I have AllRoutines and Product entities. AllRoutines can have 0 or 1 Products. Here is my AllRoutines class (some code has been omitted for clarity):
public class AllRoutines
{
[Key]
public long Id { get; set; }
public string Name { get; set; }
public string Tags { get; set; }
public int? RoutineLevelId { get; set; }
public RoutineLevel RoutineLevel { get; set; }
public Guid? ProductId { get; set; }
public virtual Product Product { get; set; }
}
Here is FluetnApi mapping (again some code is omitted):
public void MapRoutine(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<RoutineLevel>().HasKey(r => r.RoutineLevelId);
modelBuilder.Entity<AllRoutines>()
.HasKey(r => r.Id)
.Property(r => r.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<AllRoutines>()
.HasOptional(r => r.RoutineLevel)
.WithMany()
.HasForeignKey(r => r.RoutineLevelId);
modelBuilder.Entity<AllRoutines>().HasOptional(c => c.Product)
.WithMany()
.HasForeignKey(c => c.ProductId)
.WillCascadeOnDelete(false);
}
Also I am not sure if this is important or not, but there is also class CustomRoutine which inherits AllRoutines and looks like this:
public class CustomRoutine : AllRoutines
{
public DateTime DateCreated { get; set; }
public string UserId { get; set; }
public User UserWhoCreatedRoutine { get; set; }
}
The inheritance approach was Table per Hierarchy.
I've tried to add to mapping configuration this:
modelBuilder.Entity<CustomRoutine>().HasOptional(c => c.Product)
.WithMany()
.HasForeignKey(c => c.ProductId)
.WillCascadeOnDelete(false);
But the error was same. I am not sure why this is happening, because, as you can see in the code same mapping was already done (without any problems) for RoutineLevel, also I have same mapping for Product and the other class, again with no problems.
EDIT
Here is also Product class:
public class Product
{
public Guid Id { get; protected set; }
public string Code { get; set; }
public string Name { get; set; }
public bool IsFree { get; set; }
public ICollection<SubscriptionProduct> SubscriptionProducts { get; set; }
}
And FluentAPI mapping:
modelBuilder.Entity<Product>()
.HasKey(p => p.Id);
modelBuilder.Entity<Product>()
.Property(p => p.Code)
.IsRequired()
.HasMaxLength(10);
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.IsRequired()
.HasMaxLength(100);
modelBuilder.Entity<Product>()
.HasMany(p => p.SubscriptionProducts)
.WithRequired()
.HasForeignKey(p => p.ProductId)
.WillCascadeOnDelete(true);

Entity Framework mysterious error

Please help. I don`t understand why from my entity context
var stagesExist = context.WfwDocumentWorkStages
.Any(it => it.Enabled && it.ExecutionId == execution.Id
&& it.Level == execution.Level && it.ResultId == null);
value stagesExist is false
But
var stages = context.WfwDocumentWorkStages.Where(it => it.Enabled
&& it.ExecutionId == execution.Id
&& it.Level == execution.Level).ToList();
bool stagesExist = stages.Any(it=>it.ResultId == null);
value stagesExist is true??
Model:
public partial class WfwDocumentWorkScheme : EnabledEntity
{
public WfwDocumentWorkScheme()
{
this.WfwExecutionEvents = new List<WfwExecutionEvent>();
}
public int ExecutionId { get; set; }
public int Level { get; set; }
public int? RoleId { get; set; }
public string CoordinatorSid { get; set; }
public DateTimeOffset? Date { get; set; }
public int? ResultId { get; set; }
public string Comment { get; set; }
public virtual Employee Coordinator { get; set; }
public virtual EmployeeRole EmployeeRole { get; set; }
public virtual WfwEventResult WfwEventResult { get; set; }
public virtual WfwDocumentExecution WfwDocumentExecution { get; set; }
public virtual ICollection<WfwExecutionEvent> WfwExecutionEvents { get; set; }
}
Mapping
public class WfwDocumentWorkSchemeMap : EntityTypeConfiguration<WfwDocumentWorkScheme>
{
public WfwDocumentWorkSchemeMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.CoordinatorSid)
.HasMaxLength(46);
// Table & Column Mappings
this.ToTable("WfwDocumentWorkSchemes");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.ExecutionId).HasColumnName("ExecutionId");
this.Property(t => t.Level).HasColumnName("Level");
this.Property(t => t.RoleId).HasColumnName("RoleId");
this.Property(t => t.CoordinatorSid).HasColumnName("CoordinatorSid");
this.Property(t => t.Date).HasColumnName("Date");
this.Property(t => t.ResultId).HasColumnName("ResultId");
this.Property(t => t.Comment).HasColumnName("Comment");
this.Property(t => t.Enabled).HasColumnName("Enabled");
// Relationships
this.HasRequired(t => t.Coordinator)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.CoordinatorSid);
this.HasRequired(t => t.WfwDocumentExecution)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.ExecutionId);
this.HasRequired(t => t.WfwEventResult)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.ResultId);
this.HasOptional(t => t.EmployeeRole)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.RoleId);
}
}
Result model contains virtual List
public class WfwEventResult : EnabledEntity
{
public WfwEventResult()
{
this.WfwExecutionEvents = new List<WfwExecutionEvent>();
this.WfwDocumentWorkSchemes = new List<WfwDocumentWorkScheme>();
}
public string Name { get; set; }
public string Description { get; set; }
public bool Success { get; set; }
public virtual ICollection<WfwExecutionEvent> WfwExecutionEvents { get; set; }
public virtual ICollection<WfwDocumentWorkScheme> WfwDocumentWorkSchemes { get; set; }
}
The problem is this line in your mapping:
this.HasRequired(t => t.WfwEventResult)
You are effectively telling the EF that the associated FK column will never be null (although you've made it int? and have records with null value). Remember that EF uses metadata information when building SQL queries, and in this case I guess the query optimizer decides that this query will never return records (similar to .Where(it => false)) and generates a fake SQL query you see.
Shortly - make sure you always provide the correct information to EF. In this case, change the above to
this.HasOptional(t => t.WfwEventResult)
and you'll see a different (real) query and get a correct results.

Missing Information When Eager Loading With Entity Framework

When trying to eager load the PriceGridRow, the index and value properties of PriceGridColumn are populated but the Id and the ProduceGridRowId are not. If i try to explicitly include PriceGridColumns it get duplicate columns (ie. i have 10 columns but the object returned by EF has 20) and half of the the columns returned are fully populated and the other half are not.
I've been pulling what's left of my hair trying to figure out why this is occurring. Can anyone see based on my configuration why it would be acting this way? Thanks!
The code i use to get columns are:
public override PriceGrid GetLoadedById(object id)
{
var priceGrid = Entities
Include(x => x.PriceGridRows.Select(o => o.PriceGridColumns))
.FirstOrDefault(x => x.Id == (int) id);
return priceGrid;
}
Here are the classes in question
public class PriceGrid : DomainEntity<int>
{
public string Description { get; set; }
public Product Product { get; set; }
public int ProductId { get; set; }
public List<PriceGridRow> PriceGridRows
{
get { return _priceGridRow; }
set { _priceGridRow = value; }
}
}
public class PriceGridRow : DomainEntity<int>
{
public PriceGrid PriceGrid { get; set; }
public int PriceGridId { get; set; }
public ProductOption ProductOption { get; set; }
public int ProductOptionId { get; set; }
public List<PriceGridColumn> PriceGridColumns { get; set; }
}
And finally the third level of nesting
public class PriceGridColumn : DomainEntity<int>
{
public PriceGridRow PriceGridRow { get; set; }
public int PriceGridRowId { get; set; }
public int Index { get; set; }
public decimal Value { get; set; }
}
Here are my mapping files
public class PriceGridMap : EntityTypeConfiguration<PriceGrid>
{
public PriceGridMap()
{
HasKey(x => x.Id);
Property(x => x.Description);
HasRequired(x => x.Product);
HasMany(x => x.PriceGridRows)
.WithRequired(x => x.PriceGrid)
.HasForeignKey(x => x.PriceGridId)
.WillCascadeOnDelete();
}
}
public class PriceGridRowMap : EntityTypeConfiguration<PriceGridRow>
{
public PriceGridRowMap()
{
HasKey(x => x.Id);
HasRequired(x => x.ProductOption);
HasMany(x => x.PriceGridColumns)
.WithRequired(x => x.PriceGridRow)
.HasForeignKey(x => x.PriceGridRowId)
.WillCascadeOnDelete();
}
}
public class PriceGridColumnMap : EntityTypeConfiguration<PriceGridColumn>
{
public PriceGridColumnMap()
{
HasKey(x => x.Id);
Property(x => x.Index);
Property(x => x.Value);
HasRequired(x => x.PriceGridRow);
}
}
Try to remove this mapping line from PriceGridColumnMap:
HasRequired(x => x.PriceGridRow);
which basically means that the relationship the PriceGridRow navigation property belongs to does not have an inverse navigation property. It is a shortcut for:
HasRequired(x => x.PriceGridRow)
.WithMany()...
But this is in contradiction with the mapping in PriceGridRowMap:
HasMany(x => x.PriceGridColumns)
.WithRequired(x => x.PriceGridRow)...
which says that the PriceGridRow navigation property does have an inverse navigation property, namely PriceGridColumns.