Here's my code:
base class:
public class BaseEnt
{
[Key]
public int ID { get;set; }
public DateTime InsertDate { get; set; }
public int InsertUserID { get; set; }
public DateTime UpdateDate { get; set; }
public int UpdateUserID { get; set; }
[Timestamp]
public byte[] Timestamp { get; set; }
public virtual User InsertUser { get; set; }
public virtual User UpdateUser { get; set; }
}
user entity:
public class User:BaseEnt
{
public string Username { get; set; }
public string Fullname { get; set; }
public virtual ICollection<User> InsertedUsers { get; set; }
public virtual ICollection<User> UpdatedUsers { get; set; }
}
model creating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasRequired(t => t.InsertUser)
.WithMany(t=>t.InsertedUsers)
.HasForeignKey(t => t.InsertUserID).WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
.HasRequired(t => t.UpdateUser)
.WithMany(t=>t.UpdatedUsers)
.HasForeignKey(t => t.UpdateUserID).WillCascadeOnDelete(false);
}
Seed:
protected override void Seed(MCFDataContext context)
{
context.Users.Add(new Entities.User {ID=1,Fullname="Rusty Boi ",Username="jhaskdhaksdhk",InsertUserID=1,UpdateUserID=1,UpdateDate=DateTime.Now,InsertDate=DateTime.Now });
}
and here's the error i encountered in the seed part:
{"Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values."}
what you have here is some sort of "chicken and egg" problem. Possible solutions:
Make the foreign keys InsertUserID and UpdateUserID nullable
Do a design change: Maybe the user table shouldn't have InsertUserID, UpdateUserID. this could be solved by introducing another base class which doesn't have the InsertUserID and UpdateUserID properties or something similar
Related
I'm using entity core 3. I have 2 classes User and Ticket. User may have many Ticket's to me and many Ticket's from me. Ticket should have User-sender and User-receiver. I did so:
public class User
{
public int Id { get; set; }
public string PasswordHash { get; set; }
public string Email { get;
public ICollection<Ticket> TicketsToMe { get; set; }
public ICollection<Ticket> TicketsFromMe { get; set; }
}
public class Ticket
{
public int Id { get; set; }
public string Title { get; set; }
public int UserToId { get; set; }
public int UserFromId { get; set; }
public User UserTo { get; set; }
public User UserFrom { get; set; }
}
And I got the error: Unable to determine the relationship represented by navigation property 'Ticket.UserTo' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Do you have any ideas?:)
You can use one of these
1 - Metadata. you can use InverseProperty to define the relationships.
if you use the metadata you should set UserToId and UserFromId to Nullable
public class User
{
public int Id { get; set; }
public string PasswordHash { get; set; }
public string Email { get; set; }
[InverseProperty("UserTo")]
public ICollection<Ticket> TicketsToMe { get; set; }
[InverseProperty("UserFrom")]
public ICollection<Ticket> TicketsFromMe { get; set; }
}
2 - FluentApi
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(a => a.TicketsFromMe)
.WithOne(a => a.UserFrom)
.HasForeignKey(a => a.UserFromId).OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<User>()
.HasMany(a => a.TicketsToMe)
.WithOne(a => a.UserTo)
.HasForeignKey(a => a.UserToId).OnDelete(DeleteBehavior.Restrict);
}
I have the following:
public class Event : IEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("date")]
public DateTimeOffset Date { get; set; }
[JsonProperty("distance")]
public int Distance { get; set; }
[JsonProperty("verticalAscend")]
public int VerticalAscend { get; set; }
[ForeignKey("User")]
[JsonProperty("userId")]
public Guid UserId { get; set; }
//attending
public DateTimeOffset DateCreated { get; set; }
public DateTimeOffset DateModified { get; set; }
[JsonProperty("user")]
public virtual User User { get; set; }
[JsonProperty("comments")]
public virtual ICollection<Comment> Comments { get; set; }
[JsonProperty("attending")]
public virtual ICollection<User> AttendingList { get; set; }
}
And:
public class User : IEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("profilePicUrl")]
public string ProfilePicUrl { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("surname")]
public string LastName { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
public DateTimeOffset DateCreated { get; set; }
public DateTimeOffset DateModified { get; set; }
public virtual ICollection<Event> AttendingEvents { get; set; }
[InverseProperty("User")]
public virtual ICollection<Event> Events { get; set; }
}
Relationships:
Event:
Many Users attending (AttendingList)
User:
Can attend many events (AttendingEvents)
Can create multiple events (Events)
There exists a many-many relationship between the Event.AttendingList and User.AttendingEvents.
There exists 0-many relationship between Event.User and User.Events, with ForeignKey as UserId.
I am trying to configure these with Fluent API, and using the InverseProperty to configure the other side of the relationship, mapping back to Event.User, but getting the following error:
Introducing FOREIGN KEY constraint 'FK_dbo.UserEvents_dbo.Events_Event_Id' on table 'UserEvents' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I am unsure on how to solve this relationship on one table. What am I doing wrong?
In the DbContext configure your models as follows:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Event>().HasRequired(e => e.User)
.WithMany(u => u.Events)
.HasForeignKey(e => e.UserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<User>()
.HasMany<Event>(s => s.AttendingEvents)
.WithMany(c => c.AttendingList)
.Map(cs =>
{
cs.MapLeftKey("UserId");
cs.MapRightKey("EventId");
cs.ToTable("UserEvents");
});
}
I have the following two entities:
public class Company
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string Town { get; set; }
public string Country { get; set; }
}
This corresponds to two DB tables:
Company:
Id uniqueidentifier
Name varchar
Address:
Id uniqueidentifier
Town varchar
Country varchar
RelationId uniqueidentifier
RelationId is the foreign key which stores the link back to CompanyId.
I can not change either the classes or the tables.
I am trying to figure out how to represent this construct in code first EFCore.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Company>().ToTable("Companies");
modelBuilder.Entity<Address>().ToTable("Addresses");
modelBuilder.Entity<Company>().HasKey(c => c.Id);
modelBuilder.Entity<Address>().HasKey(c => c.Id);
???????????????????????
}
What am I missing in the code above to prevent the creation of a CompanyId foreign key and use the 'RelationId' instead.
Create a Guid RelationId and a Company Company properties in Address, as purposed by #TanvirArjel and use the following fluent configuration:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
.....
modelBuilder.Entity<Company>()
.HasOne(c => c.Address)
.WithOne(a => a.Company)
.HasForeignKey(a => a.RelationId);
}
If an address can have more than one company, change the WithOne by WithMany and the Company property type to ICollection<Company>
Here is the solution for your requirement :
public class Company
{
public Guid Id { get; set; }
public string Name { get; set; }
//remove virtual keyword as there is no lazy loading in entityframework core
public ICollection<Address> Addresses { get; set; }
}
public class Address
{
public Guid Id { get; set; }
[ForeignKey("Company ")]
public Guid RelationId { get; set; }
public string Town { get; set; }
public string Country { get; set; }
//remove virtual keyword as there is no lazy loading in entityframework core
public Company Company {get; set;}
}
Using Fluent API:
public class YourDbContext : DbContext
{
public DbSet<Company> Companies { get; set; }
public DbSet<Address> Addresses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>()
.HasOne(p => p.Company)
.WithMany(b => b.Addresses);
}
}
I just started using Code first approach for creating databases. I have following 3 tables :
public class TagDatabase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TagID { get; set; }
public string TagName { get; set; }
public string Description { get; set; }
public int Count { get; set; }
[ForeignKey("TagTypes")]
public virtual int TagTypeID { get; set; }
public virtual ICollection<TagTypesDb> TagTypes { get; set; }
[ForeignKey("Users")]
public virtual int CreatedBy { get; set; }
public virtual UsersDb Users { get; set; }
}
public class TagTypesDb
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TagTypeID { get; set; }
public string TagTypeName { get; set; }
}
public class UsersDb
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserID { get; set; }
public string UserName { get; set; }
}
Here TagDatabse and User and TagType have 1 to 1 replationship. The fluent API code which i used for this is :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<TagDatabase>()
.HasOptional(a => a.TagTypes)
.WithMany()
.HasForeignKey(u => u.TagTypeID);
modelBuilder.Entity<TagDatabase>()
.HasRequired(a => a.Users)
.WithMany()
.HasForeignKey(u => u.CreatedBy);
}
Now my issue is whenever i am trying to insert data in TagDatabase i got this exception :
TagDatabase_TagTypes: : Multiplicity conflicts with the referential constraint in Role 'TagDatabase_TagTypes_Target' in relationship 'TagDatabase_TagTypes'. Because all of the properties in the Dependent Role are non-nullable, multiplicity of the Principal Role must be '1'.
The TagTypeId property is allowed nulls .so i used HasOptional() in OnModelCreating method.
Cananybody please tell me how to solve this issue and what i am missing here ?
You should make the foreign key property nullable if the corresponding relationship is optional.
public class TagDatabase
{
//sniff...
[ForeignKey("TagTypes")]
public virtual int? TagTypeID { get; set; } //Since TagTypes is optional, this should be nullable
public virtual ICollection<TagTypesDb> TagTypes { get; set; }
//sniff...
}
I have aproject with codefirst migrations wiht the following classes:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Chat> Chats { get; set; }
}
and
public class Chat
{
[Key, Column(Order = 0)]
public int User1Id { get; set; }
public virtual User User1 { get; set; }
[Key, Column(Order = 1)]
public int User2Id { get; set; }
public virtual User User2 { get; set; }
public string Channel { get; set; }
}
The Idea is A chat has two users, and the chat Primary key is a composite key of the two user Ids, which are foreign keys.
A user has also a list of chats, in which he participates.
now when I try to run this, I get the following error:
Introducing FOREIGN KEY constraint 'FK_dbo.Chat_dbo.User_User2Id' on table 'Chat' 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.
I kind of understand what's happening, but I don't know how to fix it. Tried this (from a topic here somewhere):
public DbSet<User> Users { get; set; }
public DbSet<Chat> Chats { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Chat>()
.HasRequired(s => s.User1)
.WithMany()
.WillCascadeOnDelete(true);
modelBuilder.Entity<Chat>()
.HasRequired(s => s.User2)
.WithMany()
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
but with no result, i still get the error. Can anyone shine some light on this matter?
try
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Chat> InitiatedChats { get; set; }
public virtual ICollection<Chat> ParticipantInChats { get; set; }
}
public class Chat
{
[Key, Column(Order = 0)]
public int User1Id { get; set; }
public virtual User User1 { get; set; }
[Key, Column(Order = 1)]
public int User2Id { get; set; }
public virtual User User2 { get; set; }
public string Channel { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Chat>()
.HasRequired(s => s.User1)
.WithMany(u => u.InitiatedChats)
.HasForeignKey(s => s.User1Id)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Chat>()
.HasRequired(s => s.User2)
.WithMany(u => u.ParticipantInChats)
.HasForeignKey(s => s.User2Id)
.WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
The anwser comes from this post