I have an Offer entity that provides a link between two users in my system.
public class Offer
{
public OfferStatus Status { get; set; }
public decimal Amount {get; set; }
public virtual User Provider { get; set; }
public virtual User Receiver { get; set; }
}
This User entity has primary key of:
public string Id { get; set; }
I would like to have the two users ID strings appear in the Offer table like so:
public class Offer
{
public OfferStatus Status { get; set; }
public decimal Amount {get; set; }
public string ProviderId { get; set; }
public string ReceiverId { get; set; }
public virtual User Provider { get; set; }
public virtual User Receiver { get; set; }
}
I have tried:
public class Offer
{
public OfferStatus Status { get; set; }
public decimal Amount {get; set; }
public string ProviderId { get; set; }
public string ReceiverId { get; set; }
[ForeignKey(nameof(ProviderId))]
public virtual User Provider { get; set; }
[ForeignKey(nameof(ReceiverId))]
public virtual User Receiver { get; set; }
}
This is how I usually set foreign keys but usually I only have one of them and I use the naming convention magic that EF provides so I know what I have done here is wrong but I am confused how I am supposed to set their foreign key properties.
Related
Say I want to model a relationship between users and auctions. A user can host an auction in which other users can bid in, while he can also bid in auctions of other users. So I want a User table, an Auction table with a foreign key reference to the User table, and an AuctionBidders table.
What do I have to add/change in the code below or in the OnModelCreating() method to make it work?
public class User
{
public int Id { get; set; }
public ICollection<Auction> Auctions { get; set; }
}
public class Auction
{
public int Id { get; set; }
public User Host { get; set; }
public ICollection<User> Bidders { get; set; }
}
Assuming that one action can have only have one Host, but the same user can be a Host for many auctions, you have to add relations for Host too
public class User
{
public int Id { get; set; }
[InverseProperty(nameof(Auction.Host))]
public ICollection<Auction> Hosts { get; set; }
public ICollection<Auction> Auctions { get; set; }
}
public class Auction
{
public int Id { get; set; }
public int HostId { get; set; }
[ForeignKey(nameof(HostId))]
[InverseProperty(nameof(User.Hosts))]
public User Host { get; set; }
public ICollection<User> Users { get; set; }
}
ef core 5+ will create the third table for you but I would prefer to add it explicetely since you have non standard db structrure
public class AuctionUser
{
[Key]
public int Id { get; set; }
public int AuctionId { get; set; }
[ForeignKey(nameof(AuctionId))]
[InverseProperty("Users")]
public virtual Auction Auction { get; set; }
public int UserId { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("Auctions")]
public virtual User User { get; set; }
}
I am having issues with making the navigation properties correctly since I get the error
The Foreign key component ID is not a declared property on type Administrator.
My model basically consists of a base class User which has two derived classes Administrator and Common user. I believe this is a one to many relation since there can be multiple common and administrator users.
My classes look like this:
[Table("User")]
public class User
{
[Key]
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public DateTime RegisterDate { get; set; }
public virtual ICollection<Common> CommonUsers { get; set; }
public virtual ICollection<Administrator> Administrators { get; set;}
}
public class Administrator : Usuario
{
[ForeignKey("User")]
public int ID { get; set; }
public virtual User User { get; set; }
}
public class Common : Usuario
{
[ForeignKey("User")]
public int ID { get; set; }
public virtual User User { get; set; }
}
I set the foiregn key on both ID attributes in the derived classes to reference the User ID which is the primary key for the table.
Any input would be appreciated.
Semantically your construction
public virtual ICollection<Common> CommonUsers { get; set; }
public virtual ICollection<Administrator> Administrators { get; set;}
mean that a single user can be multiple Administrators and each Administrator can be assigned to a single user.
public virtual User User { get; set; }
From the logic explained it should vise versa.
public class User
{
[Key]
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public DateTime RegisterDate { get; set; }
//public virtual ICollection<Common> CommonUsers { get; set; }
public virtual Administrator Administrators { get; set;}
}
public class Administrator : Usuario
{
//Primary key is required but not defined
[ForeignKey("User")]
public int ID { get; set; }
//same admin role applies to many users
public virtual ICollection<User> User { get; set; }
}
Also note that class name User may shadow / conflict with System.Security.Principal.User
Most probably you mean
public class Usuario // User
{
[Key]
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public DateTime RegisterDate { get; set; }
//public virtual ICollection<Common> CommonUsers { get; set; }
//public virtual ICollection<Administrator> Administrators { get; set;}
//define 1-to-1(0)
public virtual Common CommonUsers { get; set; }
public virtual Administrator Administrators { get; set;}
}
public class Administrator : Usuario
{
[ForeignKey("User")]
public int ID { get; set; }
public virtual User User { get; set; }
}
I have a model:
public class Delivery
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid BusinessId { get; set; }
public virtual ICollection<PriceDisc> PriceDisc { get; set; }
}
public class PriceDisc
{
public Guid Id { get; set; }
public decimal Amount { get; set; }
public Guid BusinessId { get; set; }
}
How to create relation one to many between Delivery.BusinessId and PriceDisc.BuissnessId?
Thanks
you have already created a one to many relationship between them Delivery hold collection of PriceDisc in your code so for one Delivery.BusinessId you have collection of PriceDisc.BusinessId
How to define in Entity Framework 6, which columns will be used to reference data in an ICollection<>?
For example, we have a simple User-Information relation, were i can get all information from a user which updated or created the information:
public class User
{
public int UserId
{
get;
get;
}
// Here is the problem, how to define that EF
// Has to use the CreateUser column
public virtual ICollection<User> User_CreateUser
{
get;
set;
}
// Here is the problem, how to define that EF
// Has to use the UpdateUser column
public virtual ICollection<User> User_UpdateUser
{
get;
set;
}
}
public class Information
{
public int InfoId
{
get;
set;
}
public int CreateUser
{
get;
set;
}
public int UpdateUser
{
get;
set;
}
[System.ComponentModel.DataAnnotations.Schema.ForeignKey("CreateUser")]
public virtual User User_CreateUser
{
get;
set;
}
[System.ComponentModel.DataAnnotations.Schema.ForeignKey("UpdateUser")]
public virtual User User_UpdateUser
{
get;
set;
}
}
But i don't know, how to map this. For the simple foreign-keys it was easy over annotations.
I use database first but generating the models on my own. (Which works pretty good besides the ICollection<>.
Thank you!
You've marked your second foreign key as User but it should be int.
public int UpdateUser { get; set; }
Try this:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace Test
{
public class User
{
public int UserId { get; set; }
public virtual ICollection<User> User_CreateUser { get; set; }
public virtual ICollection<User> User_UpdateUser { get; set; }
}
public class Information
{
public int InfoId { get; set; }
public int CreateUser { get; set; }
public int UpdateUser { get; set; }
[ForeignKey("CreateUser")]
public virtual User User_CreateUser { get; set; }
[ForeignKey("UpdateUser")]
public virtual User User_UpdateUser { get; set; }
}
}
yesterday I created database in Management Studio and now I want to create it in program using EF Code First.
Here is link to my database: http://s11.postimg.org/6sv6cucgj/1462037_646961388683482_1557326399_n.jpg
And what I did:
public class GameModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string TotalTime { get; set; }
public DateTime RouteStartTime { get; set; }
public DateTime RouteEndTime { get; set; }
public int MaxPlayersPerTeam { get; set; }
public int CityId { get; set; }
public int CreatorId { get; set; }
[InverseProperty("Id")]
[ForeignKey("CreatorId")]
//public int TeamId { get; set; }
//[ForeignKey("TeamId")]
public virtual UserModel Creator { get; set; }
public virtual CityModel City { get; set; }
//public virtual TeamModel WinnerTeam { get; set; }
}
public class RegionModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<CityModel> Cities { get; set; }
}
public class CityModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int RegionId { get; set; }
public virtual RegionModel Region { get; set; }
public virtual ICollection<UserModel> Users { get; set; }
public virtual ICollection<GameModel> Games { get; set; }
}
public class UserModel
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public DateTime RegistrationDate { get; set; }
public string FacebookId { get; set; }
public int CityId { get; set; }
public virtual CityModel City { get; set; }
public virtual IEnumerable<GameModel> Games { get; set; }
}
For now I wanted to create 4 tables but I have some problems... I want to make CreatorId in GameModel, but it doesn't work... When i wrote UserId instead of CreatorId it was working ( without [InverseProperty("Id")] and [ForeignKey("CreatorId")]).
This is what i get:
The view 'The property 'Id' cannot be configured as a navigation property. The property must be a valid entity type and the property should have a non-abstract getter and setter. For collection properties the type must implement ICollection where T is a valid entity type.' or its master was not found or no view engine supports the searched locations.
edit:
I changed it like this:
public int CityId { get; set; }
public int CreatorId { get; set; }
[ForeignKey("CityId")]
public virtual CityModel City { get; set; }
[ForeignKey("CreatorId")]
public virtual UserModel Creator { get; set; }
And there is another problem.
The view 'Introducing FOREIGN KEY constraint 'FK_dbo.UserModels_dbo.CityModels_CityId' on table 'UserModels' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.' or its master was not found or no view engine supports the searched locations.
And I have no idea how to solve it.
The InversePropertyAttribute specifies, which navigation property should be used for that relation.
A navigation property must be of an entity type (the types declared in your model, GameModel for example) or some type implementing ICollection<T>, where T has to be an entity type. UserModel.Id is an int, which clearly doesn't satisfy that condition.
So, the inverse property of GameModel.Creator could be UserModel.Games if you changed the type to ICollection<GameModel>, or had to be left unspecified. If you don't specify an inverse property, EF will try to work everything out on its own (in this case it would properly recognize GameModel.Creator as a navigation property, but UserModel.Games would most likely throw an exception, as it is neither an entity type, nor does it implement ICollection<T> with T being an entity type, nor is it a primitive type from a database point of view). However, EF's work-everything-out-by-itself-magic doesn't cope too well with multiple relations between the same entity types, which is when the InversePropertyAttribute is needed.
A quick example that demonstrates the problem:
class SomePrettyImportantStuff {
[Key]
public int ID { get; set; }
public int OtherId1 { get; set; }
public int OtherId2 { get; set; }
[ForeignKey("OtherId1")]
public virtual OtherImportantStuff Nav1 { get; set; }
[ForeignKey("OtherId2")]
public virtual OtherImportantStuff Nav2 { get; set; }
}
class OtherImportantStuff {
[Key]
public int ID { get; set; }
public virtual ICollection<SomePrettyImportantStuff> SoldStuff { get; set; }
public virtual ICollection<SomePrettyImportantStuff> BoughtStuff { get; set; }
}
Here, EF knows that it has to generate 2 FKs from SomePrettyImportantStuff to OtherImportantStuff with the names Id1 and Id2, but it has no way to tell which of the IDs refers to the entity where it was sold from and which is the one it was bought from.
Edit: How to fix the cyclic reference problem
To fix that problem, your context class should override OnModelCreating and configure the foreign keys which shouldn't cascade on delete accordingly, like this:
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<CityModel>().HasMany(c => c.Users).WithRequired(u => u.City)
.HasForeignKey(u => u.CityId).WillCascadeOnDelete(value: false);
// Add other non-cascading FK declarations here
base.OnModelCreating(builder);
}