I'm trying to make an insert in a SQL database using Entity Framework 6 and I'm stuck on this issue that I cannot solve.
The error that I keep getting is :
UpdateException: Entities in 'Connect.CompanyFinancialDetails' participate in the 'Company_CompanyFinancialDetails' relationship. 0 related 'Company_CompanyFinancialDetails_Source' were found. 1 'Company_CompanyFinancialDetails_Source' is expected
I have these 2 entities:
public class Company
{
public long CUI { get; set; }
public string UserName { get; set; }
public string CompanyName { get; set; }
public string Symbol { get; set; }
public int? SharesCount { get; set; }
public decimal? SharePrice { get; set; }
public virtual Account Account { get; set; }
public virtual CompanyFinancialDetails CompanyFinancialDetails { get; set; }
}
public class CompanyFinancialDetails
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
// other properties
public decimal? NumberOfEmployees { get; set; }
public virtual Company Company { get; set; }
}
This is the Fluent API configuration:
public DbSet<Account> SignUpModels { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<CompanyFinancialDetails> CompanyFinancialDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>()
.HasKey(k => k.Id)
.HasOptional(s => s.Company)
.WithRequired(d => d.Account);
modelBuilder.Entity<Company>()
.HasKey(k => k.CUI)
.HasOptional(s => s.CompanyFinancialDetails)
.WithRequired(d => d.Company);
}
The relationship that I want to have is 1-many (one Company has many CompanyFinancialDetails).
This is the code where I add the objects to the database:
Company co = Context.Find(username);
foreach (CompanyFinancialDetails s in c)
{
s.Company = co;
}
a.CompanyFinancialDetails.AddRange(c);
a.SaveChanges();
I get a list of CompanyFinancialDetails and I add them using the AddRange method. I had this issue before and what I did was to add the virtual property object to the object that I wanted to insert in the database and it worked. This is what I tried to do here: the Find() method gets the company object that is related to the CompanyFinancialDetails and for each CompanyFinancialDetails object an Company virtual property is adding the related company object.
Well, it didn't work, when the SaveChanges() method is called, I get that error. Any help would be appreciated.
Related
I am working on a messenger API, and it goning be something like discord which someone sends a friend request to another user, and if the user accepted, they start messaging. as you know each FriendRequest has two contacts, sender and receiver, there are two ways to implement this relationship, one way is to define a many-to-many relationship between FriendRequest and contact and limit the FriendRequest's contacts to two. the other way is to define two properties in FriendRequest, SenderContact and ReceiverContact.
I chose the second way which each FriendRequest should have two foreign keys with two contacts. But EF added another foreign key automatically.
I just want to know two things
1: Is the second way that I chose a good way? Is there any better way to implement this situation?
2: Can I prevent EF from creating the ContactId column?
OnModelCreating in MyConext:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Contact>().HasMany<FriendRequest>().WithOne(f => f.FromContact);
builder.Entity<Contact>().HasMany<FriendRequest>().WithOne(f => f.ToContact);
base.OnModelCreating(builder);
}
FriendRequest:
public class FriendRequest
{
public int Id { get; set; }
public Contact FromContact { get; set; }
public Contact ToContact { get; set; }
public string Text { get; set; }
}
Contact:
public class Contact
{
[Key]
public int Id { get; set; }
public int UserId { get; set; }
public string Username { get; set; }
public ICollection<Chat> Chats { get; set; }
public ICollection<FriendRequest> FriendRequests { get; set; }
public ICollection<Contact> Friends { get; set; }
}
Your approach seems okay to me, but you have a configuration error.
Your contact object should be
public class Contact
{
[Key]
public int Id { get; set; }
public int UserId { get; set; }
public string Username { get; set; }
public ICollection<Chat> Chats { get; set; }
public ICollection<FriendRequest> SentFriendRequests { get; set; }
public ICollection<FriendRequest> ReceivedFriendRequests { get; set; }
public ICollection<Contact> Friends { get; set; }
}
FriendRequest can stay the same, tho it is recommended to define a foreign key
public class FriendRequest
{
public int Id { get; set; }
public Contact FromContact { get; set; }
public Contact ToContact { get; set; }
public string Text { get; set; }
}
And the configuration
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Contact>()
.HasMany<FriendRequest>(c => c.SentFriendRequests)
.WithOne(f => f.FromContact);
builder.Entity<Contact>()
.HasMany<FriendRequest>(c => c.ReceivedFriendRequests)
.WithOne(f => f.ToContact);
base.OnModelCreating(builder);
}
I always take a second look at the MS documentation when configuring relations, I recommend you do that.
I have the following entities
public class Course
{
public long Id { get; set; }
public virtual ICollection<User> Users{ get; set; }
public virtual ICollection<UserCourse> CourseUsers { get; set; }
}
public class User
{
public long Id { get; set; }
public virtual ICollection<Course> Courses { get; set; }
public virtual ICollection<UserCourse> UserCourses { get; set; }
}
public class UserCourse
{
public long UserId { get; set; }
public User User { get; set; }
public long CourseId { get; set; }
public Course Course { get; set; }
public bool IsRequired { get; set; }
}
with the following mappings for
UserCourse mapping :
builder
.HasOne(nav => nav.User)
.WithMany(self => self.UserCourses)
.HasForeignKey(fk => fk.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder
.HasOne(nav => nav.Course)
.WithMany(self => self.CourseUsers)
.HasForeignKey(fk => fk.CourseId)
.OnDelete(DeleteBehavior.Cascade);
and the User mapping
builder
.HasMany(nav => nav.Courses)
.WithMany(nav => nav.Users);
When trying to create a new migration I'm not exactly sure why I'm getting this.
Cannot use table 'UserCourse' for entity type 'UserCourse' since it is
being used for entity type 'UserCourse(Dictionary<string, object>)'
and potentially other entity types, but there is no linking
relationship. Add a foreign key to 'UserCourse' on the primary key
properties and pointing to the primary key on another entity typed
mapped to 'UserCourse'.
I understand what the error is, but not sure how to force the UserCourse mapping to use the User mapping generated join table or vice-versa
Also, I need the direcat mapping for OData, and the indirect mapping using the join entity to conduct operations on DbSet<UserCourse>
The public virtual ICollection<User> Users{ get; set; } in Course entity and the the public virtual ICollection<Course> Courses { get; set; } in Users entity are redundant. The entities should look more like this
public class Course
{
public long Id { get; set; }
public virtual ICollection<UserCourse> UserCourses { get; set; }
}
public class User
{
public long Id { get; set; }
public virtual ICollection<UserCourse> UserCourses { get; set; }
}
public class UserCourse
{
public long UserId { get; set; }
public User User { get; set; }
public long CourseId { get; set; }
public Course Course { get; set; }
}
And the OnModelCreating method should have this code
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserCourse>()
.HasKey(uc => new { uc.UserId, uc.CourseId });
modelBuilder.Entity<UserCourse>()
.HasOne(uc => uc.Course)
.WithMany(c => c.Users)
.HasForeignKey(uc => uc.CourseId);
modelBuilder.Entity<UserCourse>()
.HasOne(uc => uc.User)
.WithMany(c => c.Courses)
.HasForeignKey(uc => uc.UserId);
}
If you use EF core 5 you can directly skip the join table. It will be generated and handled by EF behind the scenes. More on the topic here https://www.thereformedprogrammer.net/updating-many-to-many-relationships-in-ef-core-5-and-above/
Hi I have problem with EF Core insert entity. The problem is that I need to insert new entity with relation to another one which is already existing. I have created the relations with fluent API. I have done this for two times. First I am creating car and adding the last edited by field with Identity user and all works but when I am trying to do the same with another entity it crashes down with
My fluent APi code which works good:
builder.Entity<Car>()
.HasOne(x => x.Owner)
.WithMany(x => x.OwnerCars)
.HasForeignKey(x => x.OwnerId);
Here is car entity:
public class Car : CarBase
{
[Key]
public int CarId { get; set; }
public bool IsTrailer { get; set; }
public virtual TrailerType TrailerType { get; set; }
public virtual int? TrailerTypeId { get; set; }
public virtual ApplicationUser Owner { get; set; }
public virtual string OwnerId { get; set; }
}
and here is Application user entity
public class ApplicationUser : IdentityUser
{
[MaxLength(100)]
public string Address { get; set; }
public DateTime CreatedDateTime { get; set; }
public DateTime LastEditationDateTime { get; set; }
public virtual ApplicationUser LastEditedBy { get; set; }
public bool IsDeleted { get; set; }
public virtual DateTime DeletedDateTime { get; set; }
public ICollection<DriverLicenseApplicationUser> DriverLicenses { get; set; }
public ICollection<RideApplicationUser> Rides { get; set; }
public ICollection<Car> OwnerCars { get; set; }
public ICollection<Car> EditedCars { get; set; }
public ICollection<Trailer> EditedTrailers { get; set; }
public ICollection<Customer> EditedCustomers { get; set; }
}
To add this entity I only call this function and all works.
public Car CreateCar(Car car)
{
_context.Cars.Add(car);
return car;
}
But when I want to save this way this another entity type it shows an error. All steps are same so I do not understand this. Here I am adding the code I use to do that.
builder.Entity<Trailer>()
.HasOne(x => x.TrailerType)
.WithMany(x => x.Trailers)
.HasForeignKey(x => x.TrailerTypeId);
Here is Trailer:
public class Trailer : CarBase
{
[Key]
public int TrailerId { get; set; }
//[Required]
public virtual TrailerType TrailerType { get; set; }
public virtual int TrailerTypeId { get; set; }
}
and here is traylerTyper:
public class TrailerType:Trackable
{
//[Key]
public int TrailerTypeId { get; set; }
[MaxLength(100)]
[Required]
public string Type { get; set; }
public string Note { get; set; }
public ICollection<Car> TrailerTypeCars { get; set; }
public ICollection<Trailer> Trailers{ get; set; }
}
and the method is the same as the one already mentioned
public Trailer CreateTrailer(Trailer trailer)
{
trailer.TrailerTypeId = trailer.TrailerType.TrailerTypeId;
//_context.Attach(trailer.TrailerType);
var result = _context.Trailers.Add(trailer);
return result.Entity;
}
When I uncomment the attach it works but I think that I dont have to attach this because I have got the relation based on IDs and the example mentioned first works great. It gives me no sense. So if anyone could give me advice it would be awsome.
Here is the error I am getting:
Cannot insert explicit value for identity column in table 'TrailerTypes' when IDENTITY_INSERT is set to OFF.
It looks like the EF doesnt know that the traylertype entity already exists and is trying to insert the same entity again and the app crashes because it already exists and I am not allowing to insert IDs directly. As I said I have absolutely no idea why is this happening.
The problem is Lazy loading. Propetry from ViewModel is not completly same as property in Database and EF tracks whole graph of property in object and doesn´t recognize that it is the same object. The solution is to work only with IDs instead with whole objects.
I'm trying to make a enitity that manages membership of a user in a organization with a role. I want to restrict a user to have only one membership in an organization. I'm doing this by creating a composite key. However i get the error when i try to create the initial migrations:
InvalidOperationException: The property 'User' cannot be added to the entity type 'OrganizationLogin' because a navigation property with the same name already exists on entity type 'OrganizationLogin'.
The entity for membership
public class OrganizationLogin
{
public int OrganizationLoginId { get; set; }
public OrganizationRole Role { get; set; }
public Organization Organization { get; set; }
public OmegaUser User { get; set; }
}
My DBContext where I try to define the composite key:
public class OmegaContext : IdentityDbContext<OmegaUser,OmegaRole,int>
{
public DbSet<Log> Logs { get; set; }
public DbSet<Organization> Organizations { get; set; }
public DbSet<OrganizationLogin> OrganizationLogins { get; set; }
public DbSet<OrganizationRole> OrganizationRoles { get; set; }
public OmegaContext()
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<OrganizationLogin>(orgLogin =>
{
orgLogin.HasAlternateKey(o => new {o.User, o.Organization});
});
}
}
If i remove the OnModelCreating code, the migrations are created succesfully.
EDIT: As mentioned in the comments, the problem was that i was referencing the class and not a property that had the key of the entities
As requested, here is my solution:
public class OrganizationUnitMember
{
public int OrganizationUnitMemberId { get; set; }
public int UserId { get; set; }
public int OrganizationUnitId { get; set; }
[ForeignKey("UserId")]
public virtual OmegaUser User { get; set; }
[ForeignKey("OrganizationUnitId")]
public virtual OrganizationUnit OrganizationUnit { get; set; }
public int RoleId { get; set; }
[ForeignKey("RoleId")]
public virtual OrganizationRole Role { get; set; }
}
And the DbContext:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<OrganizationUnit>(
orgUnit =>
{
orgUnit.HasOne(ou => ou.Parent)
.WithMany(ou => ou.Children)
.OnDelete(DeleteBehavior.Restrict)
.HasForeignKey(ou => ou.ParentId);
});
builder.Entity<OrganizationUnitMember>(member =>
{
member.HasAlternateKey(m => new {m.OrganizationUnitId, m.UserId});
});
}
I had to add the ids of the referenced entities
Is there any way to Get a cascade on delete to happen when I remove a computer? Basically when I delete a computer I want it to remove the instance and all its references except Environments and Product.
Computer Entity:
public class Computer
{
[Key]
public int Id { get; set; }
public string IpAddress { get; set; }
public string Name { get; set; }
public string UserFriendlyName { get; set; }
public string Description { get; set; }
}
Instance Entity:
public class Instance
{
public Instance()
{
TestResults = new HashSet<TestResult>();
Environments = new HashSet<Environment>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public string UserFriendlyName { get; set; }
public virtual Product Product { get; set; }
public virtual Profile LastKnownProfile { get; set; }
public virtual Computer Computer { get; set; }
public virtual ICollection<TestResult> TestResults { get; set; }
public virtual ICollection<Environment> Environments { get; set; }
}
You need to define the relationships using the Fluent API. Use something like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Computer>()
.HasRequired(x => x.Instance)
.WithRequiredPrincipal(x => x.Computer)
.WillCascadeOnDelete();
modelBuilder.Entity<Instance>()
.HasRequired(x => x.LastKnownProfile)
.WithRequiredPrincipal(x => x.Instance)
.WillCascadeOnDelete();
modelBuilder.Entity<Instance>()
.HasMany(x => x.TestResults)
.WithOptional(x => x.Instance)
.WillCascadeOnDelete();
}
This is documented pretty well on MSDN: Configuring Relationships with the Fluent API
check many to many relationship.is turning off cascade delete for State and deleting the related records manually