Entity Framework Optional One-To-One with Joining Table - entity-framework

I have existing tables Assets and DownPayments, and I want to join them with AssetDownPayments:
Asset.cs:
[InverseProperty(nameof(AssetDownPayment.Asset))]
public virtual AssetDownPayment AssetDownPaymentAssignment { get; set; }
DownPayment.cs
[InverseProperty(nameof(AssetDownPayment.DownPayment))]
public virtual AssetDownPayment AssetDownPaymentAssignment { get; set; }
AssetDownPayment.cs
public class AssetDownPayment
{
public AssetDownPayment() { }
[Key, Column(Order = 0)]
[Index(IsUnique = true)]
[ForeignKey(nameof(Asset))]
public int AssetID { get; set; }
[InverseProperty(nameof(Models.Asset.AssetDownPaymentAssignment))]
public virtual Asset Asset { get; set; }
[Key, Column(Order = 1)]
[Index(IsUnique = true)]
[ForeignKey(nameof(DownPayment))]
public int DownPaymentID { get; set; }
[InverseProperty(nameof(Models.DownPayment.AssetDownPaymentAssignment))]
public virtual DownPayment DownPayment { get; set; }
}
I'm attempting to build a migration for adding AssetDownPayment and the error I get is:
Unable to determine the principal end of an association between the
types 'DAL.Models.AssetDownPayment' and
'DAL.Models.Asset'. The principal end of this
association must be explicitly configured using either the
relationship fluent API or data annotations.

That is not a one-to-one relationship, that is a many-to-many.
For a one-to-one (or one-to-zero-or-one) you do not use a joining table:
[Assets]
AssetId (PK, Identity)
Amount
Description
[Downpayment]
AssetId (PK)
Amount
Description
Then when configuring the relationship:
modelBuilder.Entity<Asset>()
.HasOptional(a => a.Downpayment)
.WithRequired(d => d.Asset);
Assuming that an asset may, or may not have a downpayment, but every downpayment should be associated to an Asset. One-to-one relationships default to using the PK on both tables to join the records. Asset "owns" the PK and can be set up with an Identity. Downpayment should be set up with [DatabaseGenerated(DatabaseGeneratedOption.None)] as it will be given it's ID based on the asset it is associated with.

Related

Identity framework composite key

I'm working with Entity Framework and identity framework (IdentityUser, IdentityRole). I have a table with a composite key (table Country) that points to the Users table.
Unfortunately, EF can only build a relation when all keys are the same, otherwise you'll get this:
The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
So, how can I handle this? Right now I have tried to add this composite key to the ApplicationUser:IdentityUser too, but in this way I have to add the composite key to all entities of the identity framework (that means user, role, claim, login, ...).
Here are my model classes:
class Country
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order = 1)]
public int ID { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order = 2)]
public int Version { get; set; }
[Required]
[ForeignKey(nameof(Chief))]
[Column(Order = 1)]
public string Chief_Id { get; set; }
[Required]
[ForeignKey(nameof(Chief)), Column(Order = 2)]
public int Chief_Version { get; set; }
public virtual ApplicationUser Chief{ get; set; }
}
class ApplicationUser : IdentityUser
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order = 1)]
public override string Id
{
get { return base.Id; }
set { base.Id = value; }
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order = 2)]
public int Version { get; set; }
}
Nico
Look into your foreign key nameof(Chief), you might not have the full relationship set up.
There is another question that might help here.

how to setup foreign key relationship in entity framework code first?

I have three entities, User, Domain and Role.
I have this class to define the relationship of the three entities:
public class UserDomainRole
{
[Key]
public int UserId { get; set; }
[Key]
public int DomainId { get; set; }
[Key]
public int RoleId { get; set; }
}
So how to I setup a foreign key relationship between UserDomainRole and other three table?
Is it something like this?
public class DeniedDomainRole
{
[Key]
public int UserId { get; set; }
public virtual User User { get; set; }
[Key]
public int DomainId { get; set; }
public virtual Domain Domain { get; set; }
[Key]
public int RoleId { get; set; }
public virtual Role Role { get; set; }
}
Then entity framework will work the relationship out?
This code will give you an exception with a message "Unable to determine composite primary key ordering"
In code first if you want to create a composite primary key then you have to use the to give the key/column order, like that:
[Key, Column(Order=1)]
Where
Order = The composite Primary key/column order on the table
public class UserDomainRole
{
[Key, Column(Order=1)]
public int UserId { get; set; }
[Key, Column(Order=2)]
public int DomainId { get; set; }
[Key, Column(Order=3)]
public int RoleId { get; set; }
}
So how to I setup a foreign key relationship between UserDomainRole and other three table? Is it something like this?
It is depending on what kind of the relationships you have:
Configure One-to-Zero-or-One Relationship:
Here, we will configure One-to-Zero-or-One relationship between two entities, e.g. Entity1 can be associated with zero or only one instance of Entity2.
http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx
Configure One-to-Zero-or-One Relationship:
Here, we will configure One-to-Zero-or-One relationship between two entities, e.g. Entity1 can be associated with zero or only one instance of Entity2.
http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx
Configure Many-to-Many relationship:
Here, we will learn how to configure Many-to-Many relationship between the Student and Course entity classes. Student can join multiple courses and multiple students can join one course.
http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
In this way you can relation with the user model
public int? UserUserId{get;set;}
public virtual User User{get;set;}
? makes nullable your foreignkey.

Referencing a "partition table" foreign key in Multi-Tenant Code-First Entity Framework

I am creating a multi-tenant application that needs to be built in a single database. To partition the tables, we have a Tenant entity whose primary key will be referenced as part of the keys of other tables that need partitioning. The Tenant entity looks like this:
public class Tenant
{
[Key]
public string TenantId { get; set; }
public string TenantName { get; set; }
}
An example of where this partitioning is used is in a Store-Item scenario, where a tenant can have multiple stores as well as multiple items. Stores can have multiple items, and their relationships are maintained in a StoreItem entity. Our current implementation looks like this:
Store Entity
public class Store
{
[Key, Column(Order = 1)]
public string TenantId { get; set; }
[Key, Column(Order = 2)]
public string StoreId { get; set; }
[ForeignKey("TenantId")]
public virtual Tenant Tenant { get; set; }
}
Item Entity
public class Item
{
[Key, Column(Order = 1)]
public string TenantId { get; set; }
[Key, Column(Order = 2)]
public string ItemId { get; set; }
[ForeignKey("TenantId")]
public virtual Tenant Tenant { get; set; }
}
StoreItem Entity
public class StoreItem
{
[Key, Column(Order = 1)]
public string TenantId { get; set; }
[Key, Column(Order = 2)]
public string StoreId { get; set; }
[Key, Column(Order = 3)]
public string ItemId { get; set; }
[ForeignKey("TenantId")]
public virtual Tenant Tenant { get; set; }
[ForeignKey("StoreId")]
public virtual Store Store { get; set; }
[ForeignKey("ItemId")]
public virtual Item Item { get; set; }
}
When we try to build the database, I encounter the ff. error:
StoreItem_Item_Target_StoreItem_Item_Source: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
StoreItem_Store_Target_StoreItem_Store_Source: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
What is wrong with the way I structured my keys? Should TenantId not be referenced as part of the Key for other entities?
The problem is that you're using [ForeignKey("ItemId")] to describe part of the relationship between StoreItem and Item but Item has multiple key columns. If you need the TenantId to be part of the key -- which you shouldn't if ItemId is enough to uniquely identify an Item record -- then I think you'd need to use the fluent API to define the relationship.
On the other hand, I'm guessing you don't need TenantId as a key column for either Item or Store, which would simplify things greatly.

Foreign Key Relationships with Entity Framework Code First (EntityData Issue)

I have two entity models, an Account and User and I am having difficulties implement foreign keys in the dependant model (User). As I am developing an Azure Mobile Service app I need to use the Entity Data interface which provides an 'Id' key field by default.
public class Account : EntityData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AccountId { get; set; }
[Required]
public string Username { get; set; }
[Required]
public string EmailAddress { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string SecurityQuestion { get; set; }
[Required]
public string SecurityAnswer { get; set; }
[Required]
public bool IsBusiness { get; set; }
public virtual User User { get; set; }
public virtual Business Business { get; set; }
}
public class User : EntityData
{
[Key, Column(Order=1)]
public virtual string Id { get; set; }
[Key, Column(Order=2), ForeignKey("Account")]
public int AccountId { get; set; }
public int UserId { get; set; }
[Required]
public string Forename { get; set; }
[Required]
public string Surname { get; set; }
public virtual Account Account { get; set; }
}
My issue occurs when I specify I want to find 'AccountId' Entity Framework interprets it as 'Account' table, 'Id' column.
Output from Code Migrations:-
User_Account_Source: : Multiplicity is not valid in Role
'User_Account_Source' in relationship 'User_Account'. Because the
Dependent Role properties are not the key properties, the upper bound
of the multiplicity of the Dependent Role must be '*'.
User_Account_Target_User_Account_Source: : The types of all properties
in the Dependent Role of a referential constraint must be the same as
the corresponding property types in the Principal Role. The type of
property 'AccountId' on entity 'User' does not match the type of
property 'Id' on entity 'Account' in the referential constraint
'User_Account'.
Any insight would be highly appreciated!
The reason why EF understands it is one-to-many relationship instead one-to-one is because you are composing your PKs with the Id property, wich is not a FK.In one-to-one relationships one end must be principal and second end must be dependent. Principal end is the one which will be inserted first and which can exist without the dependent one. Dependent end is the one which must be inserted after the principal because it has foreign key to the principal. When configuring one-to-one relationships, Entity Framework requires that the primary key of the dependent also be the foreign key, otherwise EF doesn't see it as one-to-one relation.
public class Account
{
[Key]
public int Id { get; set; }
public virtual User User{ get; set; }
}
public class User
{
[Key, ForeignKey("Account")]
public int AccountId { get; set; }
public virtual Account Account{ get; set; }
}
If you think about that, it makes sense,otherwise, the below records could happen:
Accounts
Id
11111111
22222222
Users
Id AccountId
12rr 11111111
22tt 11111111

Entity framework two-way relationship not loading includes

This is making me feel like an idiot. Entity Framework is supposed to be fairly simple, yet I can't sort this out myself and clearly I've got a fundamental misunderstanding. I hope it doesn't turn out to be an idiot-question - sorry if it is.
Three code-first objects, related to one another.
public class Schedule
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RowId { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public virtual ICollection<Charge> Charges { get; set; }
}
public class Charge
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RowId { get; set; }
public decimal Rate { get; set; }
public Type Type { get; set; }
}
public class Type
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RowId { get; set; }
public string TypeName { get; set; }
}
When I query this, I want all related types, so:
Schedule currentSchedule = _Context.Schedules
.Include("Charges.Type")
.Where(cs => cs.Start < dateWindow && cs.End > dateWindow)
.First();
In C#, this has been working fine.
The problem arises because we're not stopping at C#, but passing the data onto a javascript library called Breeze with smooths out data operations at the client end. Breeze has a bug/feature which demands that EF relationships between objects be specified at BOTH ENDS. So when I do my query above, I don't end up with any Types, because their relationship with Charge isn't directly specified.
So I change it to this:
public class Type
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RowId { get; set; }
public string TypeName { get; set; }
public virtual Charge Charge { get; set; }
}
Because virtual is a navigation property, so that should enable Breeze should now to go both ways across the relationship without changing the data structure. But EF doesn't like this. It tells me:
Unable to determine the principal end of an association between the
types 'Core.Charge' and 'Core.Type'. The principal end of this
association must be explicitly configured using either the
relationship fluent API or data annotations
Fair enough. I can see how this could be confusing. Now, my understanding is that if you define a foreign key in a dependent class, it has to be that classes' primary key. So we change it to:
public class Type
{
[Key, ForeignKey("Charge"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RowId { get; set; }
public string TypeName { get; set; }
public virtual Charge Charge { get; set; }
}
And that seems to work but ... it's stopped loading any Type information when you ask for a schedule. Messing around with the includes doesn't seem to do anything at all.
What's going on, and what have I done wrong?
You haven't only added a navigation property (Type.Charge) to an existing model/relationship. Instead you have changed the relationship completely from a one-to-many to a one-to-one relationship because by default if a relationship has only one navigation property EF assumes a one-to-many relationship. With your change you have configured a one-to-one relationship.
Those relationships have different foreign keys: The original one-to-many relationship has a separate foreign key in the Charge table (probably named Type_RowId or similar). Your new relationship has the foreign key at the other side in table Type and it is the primary key RowId. The Charges you are loading together with the Schedule probably don't have any related Type with the same primary key, hence no Type is loaded.
If you actually want to reproduce the old (one-to-many) relationship with just a navigation property at the other side you must add a collection to Type instead of a single reference:
public class Type
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RowId { get; set; }
public string TypeName { get; set; }
public virtual ICollection<Charge> Charges { get; set; }
}
Are you sure that you want to put ForeignKey on RowId, I think you may want to define some relationship like this
public class Type
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid RowId { get; set; }
public string TypeName { get; set; }
public int ChargeId { get; set; }
[ForeignKey("ChargeId")]
public virtual Charge Charge { get; set; }
}