The child/dependent side could not be determined for the one-to-one relationship. Net Core 2.2 to 3.1 - entity-framework

I'm upgrading a netcore project from version 2.2 to 3.1. I've managed to make it build but on runtime I'm getting this error:
{"The child/dependent side could not be determined for the one-to-one relationship between 'RestaurantCustomQuestionCategory.QuizLimits' and 'CustomCategoryQuizLimits.RestaurantCustomCategory'. 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."}
This is the code:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RestaurantCustomQuestionCategory>()
.HasKey(t => new {t.RestaurantId, t.QuestionCategoryId});
}
RestaurantCustomQuestionCategory:
public class RestaurantCustomQuestionCategory : IQuizTimeLimitable
{
public RestaurantCustomQuestionCategory()
{
QuizLimits = new CustomCategoryQuizLimits(this);
}
public int QuestionCategoryId { get; set; }
[ForeignKey("QuestionCategoryId")]
public CustomCategory QuestionCategory { get; set; }
public int RestaurantId { get; set; }
[ForeignKey("RestaurantId")]
public Restaurant Restaurant { get; set; }
public CustomCategoryQuizLimits QuizLimits { get; set; }
public void UpdateQuizTimeLimit(CustomCategoryQuizLimits item)
{
this.QuizLimits = item;
}
public QuizLimitsBase GetQuizLimits()
{
return QuizLimits;
}
}
CustomCategoryQuizLimits:
public class CustomCategoryQuizLimits : QuizLimitsBase
{
public CustomCategoryQuizLimits(RestaurantCustomQuestionCategory restaurantCustomCategory)
{
RestaurantCustomCategory = restaurantCustomCategory;
}
public CustomCategoryQuizLimits()
{
}
public CustomCategoryQuizLimits(
RestaurantCustomQuestionCategory restaurantCustomCategory
, QuizQuestionsLimit limitsQuizQuestionsLimit
, QuizTimeLimit limitsQuizTimeLimit
) : base(limitsQuizQuestionsLimit, limitsQuizTimeLimit)
{
RestaurantCustomCategory = restaurantCustomCategory;
}
[Column("CustomCategoryId")]
public int QuestionCategoryId { get; set; }
[Column("CustomCategory_RestaurantId")]
public int RestaurantId { get; set; }
public RestaurantCustomQuestionCategory RestaurantCustomCategory { get; private set; }
public override QuizLimitsBase GetDefault()
{
return new CustomCategoryQuizLimits();
}
public override int GetChainId()
{
return RestaurantCustomCategory.Restaurant.ChainId;
}
public override IEnumerable<int> GetRestaurantIds()
{
return new List<int>() {RestaurantCustomCategory.RestaurantId};
}
}
I'm not sure what I have to change to fix this so I would love a bit of help.

I found a solution. It seems on the transitions to 3.0 EF gets confused with one to one relationships. So I added this on the Fluent:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RestaurantCustomQuestionCategory>()
.HasKey(t => new {t.RestaurantId, t.QuestionCategoryId});
modelBuilder.Entity<RestaurantCustomQuestionCategory>()
.HasOne(t => t.QuizLimits)
.WithOne(i => i.RestaurantCustomCategory)
.HasForeignKey<CustomCategoryQuizLimits>(t => new { t.RestaurantId, t.QuestionCategoryId });
}

Related

Entity Framework Core null relationship

I have created a simple EF Core to join two tables by using relationship (HasOne). But when I run it, the query only queries the master table (Employees) without joining to the second table (Contact) and it causes the model to not bind the data.
Could someone point out what I am missing in this code shown below? Thanks
public class Employees
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public Contact Contact { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string ContactNumber { get; set; }
public Employees Employee { get; set; }
public int EmployeeId { get; set; }
}
internal class EmployeeMap : IEntityTypeConfiguration<Employees>
{
public void Configure(EntityTypeBuilder<Employees> builder)
{
builder.HasKey(x => x.EmployeeId);
builder.Property(p => p.EmployeeId).ValueGeneratedOnAdd();
builder.HasOne(x => x.Contact).WithOne(y => y.Employee).HasForeignKey<Contact>(k => k.EmployeeId);
}
}
public class ContactMap : IEntityTypeConfiguration<Contact>
{
public void Configure(EntityTypeBuilder<Contact> builder)
{
builder.HasKey(x => x.Id);
builder.Property(p => p.Id).ValueGeneratedOnAdd();
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);
}
private EmployeeResponse GetEmployeeResponse()
{
var emp = _context.Employees.FirstOrDefault();
return new EmployeeResponse
{
ContactNumber = emp!.Contact.ContactNumber,
EmployeeId = emp.EmployeeId,
};
}
Solutions:
1. Enable lazy loading:
DbContext.Configuration.LazyLoadingEnabled = true;
2. Or load it manually with .Include:
_context.Employees.Include(x => x.Contact).FirstOrDefault();
More information about navigation propertys in ef.

Including a Model from different DbContext

I am not sure how to achieve the relation between 2 DbContexts. PurchaseOrderDbContext is a Code first approach & AgencyDbContext is an existing database. How can I include the "Division" from AgencyDbContext based on PurchaseOrder DivisionId?
To start off here is a very simplified version of my code.
Purchase Order Model
namespace Website.Models.PurchaseOrders
{
public class PurchaseOrder
{
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public string Name { get; set; }
public int DivisionId { get; set; }
public int StatusID { get; set; }
public Agency.Division Division { get; set; }
}
}
Division Model (this is in a different DbContext)
namespace Website.Models.Agency
{
public class Division
{
public int DivisionId { get; set; }
public string DivisionName { get; set; }
public string DivisionShortName { get; set; }
public string DivisionAbbrev { get; set; }
public int? DivisionDirectorEmpId { get; set; }
}
}
Agency DbContext
namespace Website.Models.Agency
{
public class AgencyDbContext : DbContext
{
public Agency DbContext(DbContextOptions<AgencyDbContext> options) : base(options)
{
}
public virtual DbSet<Division> Division { get; set; }
public virtual DbSet<Section> Section { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}
PurchaseOrderDbContext
namespace Website.Models.PurchaseOrders
{
public class PurchaseOrderDbContext : DbContext
{
public PurchaseOrderDbContext(DbContextOptions<PurchaseOrderDbContext> options) : base(options)
{}
public DbSet<Status> Statuses { get; set; }
public DbSet<PurchaseOrder> PurchaseOrder { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}
I get an the error InvalidOperationException: Lambda expression used inside Include is not valid. This is referring to the Include extension on Division.
var purchaseOrder = _context.PurchaseOrder
.Include(p => p.Division)
.Include(p => p.Status)
.OrderByDescending(p => p.OrderDate);
Thank you in advance!
Probably the only way to resolve is to make a query to the first context for items you are looking for, and then populate Division property with entries from second context
public class PurchaseOrderService
{
private readonly PurchaseOrderDbContext purchaseOrderDbContext;
private readonly AgencyDbContext agencyDbContext;
public PurchaseOrderService(PurchaseOrderDbContext purchaseOrderDbContext,
AgencyDbContext agencyDbContext)
{
this.purchaseOrderDbContext = purchaseOrderDbContext;
this.agencyDbContext = agencyDbContext;
}
public PurchaseOrder Get(int id)
{
var purchaseOrder = purchaseOrderDbContext.PurchaseOrder.FirstOrDefault(x => x.ID == id);
if (purchaseOrder == null)
{
return null;
}
purchaseOrder.Division = agencyDbContext.Division.FirstOrDefault(x => x.DivisionId == purchaseOrder.DivisionId);
return purchaseOrder;
}
}

Table per Concrete Type Mapping Issue in EF Code First 4.2

I'm getting a EntityType 'User' has no key defined. Define the key for this EntityType error.
Model:
public abstract class KeyedEntityBase
{
public int ID { get; private set; }
}
public class User : KeyedEntityBase
{
public string UserName { get; private set; }
public string EmailAddress { get; private set; }
}
Context:
public class LSBPortalContext : DbContext
{
public LSBPortalContext()
: base("LSBPortalDB")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("User");
});
base.OnModelCreating(modelBuilder);
}
}
The issues was that I didn't actually map the KeyedEntityBase class. Once I did that it all worked properly.

EF 4.3 (Code First) - Custom ICollection Fails to catch new items

This is in reference to the question I asked regarding how to determine when items are added to the virtual ICollection property. As suggested, I have created a custom collection which inherits from Collection as shown below
public class EntityCollection<T> : Collection<T>
{
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
}
}
This is being used as
public class DbAppointment
{
public DbAppointment()
{
exceptionOcurrences = new EntityCollection<DbExceptionOcurrence>();
}
public virtual int AppointmentId { get; set; }
public virtual string Subject { get; set; }
public virtual string Body { get; set; }
public virtual DateTime Start { get; set; }
public virtual DateTime End { get; set; }
private ICollection<DbExceptionOcurrence> exceptionOcurrences;
public virtual ICollection<DbExceptionOcurrence> ExceptionOcurrences
{
get { return exceptionOcurrences; }
set { exceptionOcurrences = value; }
}
}
The problem is the only time the overridden InsertItem method seems to get called is if I initialise the database with a custom initialiser (example code below) and override the seed method!! What am I doing wrong?
Cheers
Abs
public class ContextInitializer : DropCreateDatabaseAlways<Context>
{
protected override void Seed(Context context)
{
new List<DbAppointment>
{
new DbAppointment{ Subject = "hello", Body="world", Start=DateTime.Now, End=DateTime.Now.AddMinutes(30)},
}.ForEach(a => context.Appointments.Add(a));
new List<DbExceptionOcurrence>
{
new DbExceptionOcurrence{ExceptionDate=DateTime.Now}
}.ForEach(eo => context.ExceptionOcurrences.Add(eo));
base.Seed(context);
}
}

Why can't I do ToList()?

I build a model as below. The relationship between Recycler and Account is 1:1.
public class MyContext : DbContext
{
public DbSet<Quoter> Quoters { get; set; }
public DbSet<Account> Accounts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>()
.HasRequired(a => a.RecyclerRef)
.WithRequiredDependent(r => r.AccountRef);
}
}
public class Quoter
{
public int QuoterId { get; set; }
public string Text { get; set; }
}
public class Recycler : Quoter
{
public string Description { get; set; }
public virtual Account AccountRef { get; set; }
}
public class Account
{
public int AccountId { get; set; }
public Recycler RecyclerRef { get; set; }
}
But, I get exceptions when I do the either of these queries:
var query1 = context.Quoters
.OfType<Recycler>()
.Include(r => r.AccountRef)
.Where(r => r.QuoterId == 1)
.ToList();
var query2 = context.Set<Recycler>()
.Include(r => r.AccountRef)
.Where(r => r.QuoterId == 1)
.ToList();
Exception shows that ResultType is “Transient.reference[POCOFirst.Quoter]”,but recommanded is “Transient.reference[POCOFirst.Recycler]”
If I remove the ToList(), it works well. But I need a list as the return value of method.
Why can't I do ToList()? Thanks
It looks like you have stumble upon this bug in EF. Another reference to the bug.
Workaround would be to remove the Include method.