I have the following two models
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
public int CurrentPeriodId { get; set; }
[ForeignKey("CurrentPeriodId")]
public virtual Period CurrentPeriod { get; set; }
public virtual ICollection<Period> Periods { get; set; }
}
public class Period
{
public int Id { get; set; }
public int AccountId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public virtual Account Account { get; set; }
}
And I am trying to run the following query:
from p in context.Periods
where p.AccountId == accountId &&
p.Id == p.Account.CurrentPeriodId
select p.StartDate
And I get a sql exception saying "Invalid column name Account_AccountId".
I know I could approach this from the Account side and do something like
from a in context.Accounts
where a.Id == id
select a.CurrentPeriod.StartDate
But I would like to know how to setup the relationship to get the other query to work. What am I missing?
We can configure a one-to-One relationship between entities using Fluent API where both ends are required, meaning that the Student entity object must include the StudentAddress entity object and the StudentAddress entity must include the Student entity object in order to save it.
One-to-one. One to one relationships have a reference navigation property on both sides. They follow the same conventions as one-to-many relationships, but a unique index is introduced on the foreign key property to ensure only one dependent is related to each principal.
The Code First primary key convention is: Property with name " Id " or {class name} + " Id " will act as the primary key for that entity. If you will run the application, it will create _MigrationHistory and Students tables where " StudentId " is the primary key of the Students table.
I think your implementation is wrong. AFAIK, You cannot define one-to-one relationship using this approach in EF.
Take a look at your generated database, you have an Account_Id
column defined in your Periods
table. Here's what you have to define:
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
public int CurrentPeriodId { get; set; }
public virtual Period CurrentPeriod { get; set; }
public virtual ICollection<Period> Periods { get; set; }
}
public class Period
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
Then, context and initializer:
public class TestContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<Period> Periods { get; set; }
static TestContext()
{
Database.SetInitializer(new DbInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>().HasRequired(a => a.CurrentPeriod).WithMany().HasForeignKey(a => a.CurrentPeriodId);
}
}
class DbInitializer : DropCreateDatabaseAlways<TestContext>
{
protected override void Seed(TestContext context)
{
context.Database.ExecuteSqlCommand("ALTER TABLE Accounts ADD CONSTRAINT uc_Period UNIQUE(CurrentPeriodId)");
}
}
For more information about One-To-One relationship, read Mr. Manavi's blog series at this address.
Update:
Based on your comment, if you want to have a reference to Account
from Period
, You can put a ForeignKey
attribute on your account's primary key.
A good sample is located at this address (the part with title "Map a One to Zero or One Relationship")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With