Identity insert when adding many to many relations EF - c#

i made a many to many relationship and the table was created with Classes and Users for a gym web app,but when i try to insert values to that table i get SqlException: Cannot insert explicit value for identity column in table 'classes' when IDENTITY_INSERT is set to OFF.
My models are
Class
public class Class
{
[Key]
public int ClassID { get; set; }
...
public List<UserClass> userClasses { get; set; }
}
User:
public class User
{
[Key]
public int UserID{ get; set; }
...
public List<UserClass> userClasses { get; set; }
}
Where they merge:
public class UserClass
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long UserClassID { get; set; }
public int UserID { get; set; }
public int ClassID { get; set; }
public User user { get; set; }
public Class #class { get; set; }
}
my context class modelbiulder function:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserClass>()
.HasKey(x => new { x.UserID, x.ClassID });
//If you name your foreign keys correctly, then you don't need this.
modelBuilder.Entity<UserClass>()
.HasOne(uc => uc.user)
.WithMany(p => p.userClasses)
.HasForeignKey(uc => uc.UserID);
modelBuilder.Entity<UserClass>()
.HasOne(uc => uc.#class)
.WithMany(t => t.userClasses)
.HasForeignKey(uc => uc.ClassID);
}
and this function that i use with ajax
public IActionResult BookTheClass(int ClassID)
{
User user = _context.users.Find(_auth.User.UserID);
Class selectedClass = _context.classes.Find(ClassID);
selectedClass.userClasses = new List<UserClass>() {
new UserClass{
user=user,
#class=selectedClass
}
};
_context.classes.Add(selectedClass);
_context.SaveChanges();
return PartialView("~/Views/PartialViews/ClassBooked.cshtml");
}
The other similar questions had a model builder problem that i dont have.

An identity column will keep track of the next free number, and you do not need to generate the ClassId by yourself. The new id can be fetched by SELECT SCOPE_IDENTITY()
If you really want to insert value to an identity column(not recommended) then you would have to switch on the Identity Insert property of your table. See the below SQL to do the same
SET IDENTITY_INSERT classes ON

Related

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Users_Agencies_UserID"

im using entity framework core 5.0 and i created my one to many relationship with fluent api.
im getting that error when i try to create a new user in my project.
let me show u to my User class:
public class User : Base
{
[Key]
public int UserID { get; set; }
public string UserName { get; set; }
public string UserSurname { get; set; }
public string UserPassword { get; set; }
public string UserEMail { get; set; }
public int? AgencyID { get; set; }
public virtual Agency Agency { get; set; }
}
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.HasKey(user => user.UserID);
}
}
and here its a Agency class which is related to User class:
public class Agency : Base
{
[Key]
public int AgencyID { get; set; }
public string AgencyName { get; set; }
public string AgencyPhoto { get; set; }
public string AgencyEMail { get; set; }
public string AgencyPhone { get; set; }
public int AgencyExportArea { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class AgencyConfiguration : IEntityTypeConfiguration<Agency>
{
public void Configure(EntityTypeBuilder<Agency> builder)
{
builder.HasKey(agency => agency.AgencyID);
builder.HasMany(us => us.Users)
.WithOne(us => us.Agency)
.HasForeignKey(au => au.UserID)
.IsRequired(false)
}
}
i know,im getting that error SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Users_Agencies_UserID". The conflict occurred in database "anan", table "dbo.Agencies", column 'AgencyID'. because there is a no data in Agency table. The thing which im trying to do is make that AgencyID foreign key optional as a nullable. in User class u can see i defined that AgencyID as a nullable.
do i really need to define that relationship as a one-to-one or zero or is there a another way to do that ?
if i have to define that relationship as a one-to-one or zero,can u show me the way how can i do that.
Since you are using EF core 5 you don't need:
public class UserConfiguration : IEntityTypeConfiguration<User>
and
public class AgencyConfiguration : IEntityTypeConfiguration<Agency>
All this code is reduntant. You have a standart one-to-many relation that EF core recognizes and configures by default. Remove all of this code and everything will be fine.
But if you are a student and need to do everything hard way, you can add this reduntant code:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>(entity =>
{
entity.HasOne(d => d.Agency)
.WithMany(p => p.Users)
.HasForeignKey(d => d.AgencyId)
.OnDelete(DeleteBehavior.ClientSetNull);
});
}
And since you are interested in a configuration, these are another redundant attributes:
public class User : Base
{
[Key]
public int UserID { get; set; }
.....
public int? AgencyID { get; set; }
[ForeignKey(nameof(AgencyId))]
[InverseProperty("Users")]
public virtual Agency Agency { get; set; }
}
public class Agency : Base
{
[Key]
public int AgencyID { get; set; }
.....
[InverseProperty(nameof(User.Agency))]
public virtual ICollection<User> Users { get; set; }
}

How to define a hierarchal table using EF core

In the application I am working on, we have a users table, TblUser. Users within this table may belong to a single, parent user. A parent user may have multiple child users.
This relationship is maintained within a table called TblUserMapping with two columns, ParentUserId and ChildUserId corresponding with the parent's and child's TblUser.Id value. TblUser.Id is an auto-incrementing value.
How can I define this within EF Core, and would it be possible to Insert a ChildUser into TblUser and use the auto-generated Id value to also create a TblUserMapping record?
Right now I have:
[Table("TblUser")]
public class TblUser
{
public TblUser()
{
ChildUsers = new List<TblUserMapping>();
}
public int Id { get; set; }
public string UserName { get; set; }
public virtual ICollection<TblUserMapping> ChildUsers { get; set; }
public virtual TblUserMapping ParentUser { get; set; }
}
[Table("TblUserMapping")]
public class TblUserMapping
{
public TblUserMapping()
{
}
public int ChildUserId { get; set; }
public int ParentUserId { get; set; }
public virtual TblUser ChildUser { get; set; }
public virtual TblUser ParentUser { get; set; }
}
public class TblUserMapping : IEntityTypeConfiguration<TblUser>
{
public void Configure(EntityTypeBuilder<TblUser> entity)
{
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Property(e => e.UserName)
.IsRequired()
.IsUnicode(false);
}
}
public class TblUserMappingMapping : IEntityTypeConfiguration<Entities.TblUserMapping>
{
public void Configure(EntityTypeBuilder<Entities.TblUserMapping> entity)
{
entity.HasKey(e => e.ChildUserId);
entity.Property(e => e.ChildUserId)
.IsRequired();
entity.Property(e => e.ParentUserId)
.IsRequired();
entity.HasOne(e => e.ParentUser)
.WithMany(e => e.ChildUsers)
.HasForeignKey(e => e.ParentUserId);
entity.HasOne(e => e.ChildUser)
.WithOne(e => e.ParentUser)
.HasForeignKey<TblUser>(e => e.Id);
}
}
But this isn't working as I had hoped when I do:
var userInformation = await _context
.Users
.Include(entity => entity.ChildUsers)
.ThenInclude(entity => entity.ChildUser)
.Where(s => s.UserName == userName)
.FirstOrDefaultAsync();
var ChildUser = new TblUser
{
UserName = userModel.UserName,
ParentUser = new TblUserMapping()
{
ParentUser = userInfo
}
};
_context.Users.Add(ChildUser);
await _context.SaveChangesAsync();
You can attach navigation properties, and Entity Framework will populate the ids automatically when it creates them. The example you have given should work, you might need to show us how you are getting userInfo before we can see what's going on.
That being said, instead of keeping a separate mapping table, I would have each child user refer directly to their parent:
[Table("TblUser")]
public class TblUser
{
public int Id { get; set; }
public string UserName { get; set; }
public int? ParentId { get; set; }
public TblUser Parent { get; set; }
// Lazy-loading is not enabled by default in EF Core, so you don't need the 'virtual' keyword
// Also, if the initialization of a member does not depend on constructor arguments, I
// prefer this syntax instead of doing it in the constructor
public ICollection<TblUser> Children { get; set; } = new List<TblUser>();
}
You can use InverseProperty attribute in your model:
[Table("TblUser")]
public class TblUser
{
public TblUser()
{
ChildUsers = new List<TblUserMapping>();
}
public int Id { get; set; }
public string UserName { get; set; }
[InverseProperty("ChildUser")]
public virtual ICollection<TblUserMapping> ChildUsers { get; set; }
[InverseProperty("ParentUser")]
public virtual TblUserMapping ParentUser { get; set; }
}
And in other model:
[Table("TblUserMapping")]
public class TblUserMapping
{
public TblUserMapping()
{
}
public int ChildUserId { get; set; }
public int ParentUserId { get; set; }
[ForeignKey("ChildUserId")]
public virtual TblUser ChildUser { get; set; }
[ForeignKey("ParentUserId")]
public virtual TblUser ParentUser { get; set; }
}
As you see I defined these relations with attributes that means no need to came in your configuration.

How to create multiple table references to one table - Entity framework

We have a requirement that several tables need to be referred in a one table as shown in the diagram.
Please note that the diagram is NOT the correct DB model but just represent what our requirement. Can you suggest a proper way to implement above in SQL Server DB and Entity Framework 6?
Example: A sales order (in SalesOrder table) can have multiple files and those uploaded file details will be stored in UploadedFile table. Likewise OrderTable and Invoice too.
So we need to have a proper DB model with FK relationships between FileUpload table with each other related table.
Note: All tables PKs are auto-increment int values and we may need add more entities (tables) in future
In order to provide you an alternative, as you said you are using Entity Framework, here is a sample of Code First implementation done on C#. You can create and update the schema via Package Manager Console migrations, within Visual Studio. I have used the Fluent API in order to define the relationships, as this is recommended over the alternative.
public class SampleContext : DbContext
{
public SampleContext()
: base("name=YourConnection")
{
}
public DbSet<SalesOrder> SalesOrders { get; set; }
public DbSet<CreditOrder> CreditOrders { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<UploadedFile> UploadedFiles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SalesOrder>()
.HasKey(so => so.Id);
modelBuilder.Entity<CreditOrder>()
.HasKey(co => co.Id);
modelBuilder.Entity<Invoice>()
.HasKey(i => i.Id);
modelBuilder.Entity<UploadedFile>()
.HasKey(u => u.Id);
modelBuilder.Entity<UploadedFile>()
.HasRequired(u => u.SalesOrder)
.WithMany(s => s.UploadedFiles)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UploadedFile>()
.HasRequired(u => u.CreditOrder)
.WithMany(c => c.UploadedFiles)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UploadedFile>()
.HasRequired(u => u.Invoice)
.WithMany(c => c.UploadedFiles)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UploadedFile>()
.Property(uf => uf.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<SalesOrder>()
.Property(so => so.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<CreditOrder>()
.Property(co => co.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Invoice>()
.Property(i => i.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
}
// Collections of navigation properties should be included in classes for a one-to-many relationship
public class SalesOrder
{
public int Id { get; set; }
public string MyColumn { get; set; }
public IList<UploadedFile> UploadedFiles { get; set; }
}
public class CreditOrder
{
public int Id { get; set; }
public string MyColumn { get; set; }
public IList<UploadedFile> UploadedFiles { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public string MyColumn { get; set; }
public IList<UploadedFile> UploadedFiles { get; set; }
}
public class UploadedFile
{
public int Id { get; set; }
public SalesOrder SalesOrder { get; set; }
public CreditOrder CreditOrder { get; set; }
public Invoice Invoice { get; set; }
public string FilePath { get; set; }
public string FileType { get; set; }
}
public class SalesOrder
{
public int Id { get; set; }
public string MyColumn { get; set; }
public IList<UploadedFile> UploadedFiles { get; set; }
}
public class CreditOrder
{
public int Id { get; set; }
public string MyColumn { get; set; }
public IList<UploadedFile> UploadedFiles { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public string MyColumn { get; set; }
public IList<UploadedFile> UploadedFiles { get; set; }
}
public class UploadedFile
{
public int Id { get; set; }
public SalesOrder SalesOrder { get; set; }
public CreditOrder CreditOrder { get; set; }
public Invoice Invoice { get; set; }
public string FilePath { get; set; }
public string FileType { get; set; }
}
Before Reading My Answer take notice in the below information:
A better answer can be found at this previous post at Foreign Key to multiple tables.
My Answer:
Refer here for more information from the Creating Tables documentation off of the MDSN page.
The design I went for gave each table there own id as the Primary Key. Then I used the UploadedFile table to add references to each of these tables in the shape of Foreign Keys.
I have created a few dummy scripts that might help you create these tables. Please let me know if this helps. Thank you!
SQL Scripts:
SalesOrder Table:
Create Table dbo.SalesOrder(
SalesOrderID int not null, identity primary key,
--enter whatever other columsn you have here
)
CreditOrder Table:
Create Table sbo.CreditOrder(
CreditOrderID int not null, identity primary key,
--enter whatever other columsn you have here
)
Invoice Table:
Create Table dbo.Invoice(
InvoiceID int not null, identity primary key,
--enter whatever other column you have here
)
UploadedFile Table:
Create table dbo.UploadedFile(
UploadFileID int not null identity primary key,
SalesOrderID int null Foreign Key References SalesOrder(SalesOrderID),
CreditOrderID int null Foreign Key References CreditOrder(CreditOrderID),
InvoiceID int null Foreign Key References CreditOrder(InvoiceID),
--enter whatever other columns you have here
)

Entity Framework - mapping one class to two tables with many to one relation

I have a class which represent a connection of a page and a tag and it looks more or less like this:
public class TagLink {
[Key]
public int Id { get; set; }
public int PageId { get; set; }
public int TagId { get; set; }
public string TagName { get; set; }
}
In my database I would like to have 2 tables: TagLinks and TagNames. First one with Id, PageId and TagId and the second one with TagId and TagName.
I would like the tag id to be a foreign key so many tag links can be assigned to a single tag name.
I gave it a try with EntityTypeConfiguration but I don't know how to configure it properly. It gives me wrong foreign keys which are built like this:
ALTER TABLE [dbo].[TagNames] WITH CHECK ADD CONSTRAINT [FK_dbo.TagNames_dbo.TagLinks_TagId] FOREIGN KEY([TagId])
REFERENCES [dbo].[TagLinks] ([TagId]);
ALTER TABLE [dbo].[TagNames] CHECK CONSTRAINT [FK_dbo.TagNames_dbo.TagLinks_TagId]
I started off with this:
public class TagLinkEntityConfiguration : EntityTypeConfiguration<TagLink>
{
public TagLinkEntityConfiguration()
{
HasKey(e => e.Id);
HasKey(e => e.TagId);
Property(e => e.Id).HasColumnName(nameof(TagLink.Id));
Property(e => e.PageId).HasColumnName(nameof(TagLink.PageId));
Property(e => e.TagId).HasColumnName(nameof(TagLink.TagId));
Property(e => e.TagName).HasColumnName(nameof(TagLink.TagName));
Map(m =>
{
m.Properties(e => new
{
e.Id,
e.PageId,
e.TagId
});
m.ToTable("TagLinks");
});
Map(m =>
{
m.Properties(e => new
{
e.TagId,
e.TagName
});
m.ToTable("TagNames");
});
}
}
How do I make it work with many to one relation? I guess the foreign key should be added on TagLinks table to reference TagId in TagNames table
Give this a try:
public class TagLink {
[Key]
public int Id { get; set; }
public int PageId { get; set; }
public int TagId { get; set; }
public Tag Tag { get; set; }
}
public class Tag {
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<TagLink> TagLinks { get; set; }
}
Skip the TagLinkEntityConfiguration definitions and let EF's code-first conventions to take over and solve the problem for you.

Many to one migrations fails on foreign key long

I have 2 models:
public class Text
{
public long Id { get; set; }
public string Text { get; set; }
}
public class User
{
public int Id { get; set; }
public ICollection<Text> Texts { get; set; }
}
My model build on user is that
e.HasMany(o => o.Texts).WithOne().HasForeignKey(d => d.Id).IsRequired();
When I try to run:
dotnet ef migrations add
I get this error:
with foreign key properties {'Id' : long} cannot target the primary
key {'Id' : int} because it is not compatible. Configure a principal
key or a set of compatible foreign key properties for this
relationship.
UPDATE:
It should be able for new models to have a collection of the table Texts like:
public class Customer
{
public int Id { get; set; }
public ICollection<Text> Texts { get; set; }
}
....
e.HasMany(o => o.Texts).WithOne().HasForeignKey(d => d.Id).IsRequired();
Had similar problem using EF Core but didn't want to include the (equivalent in my class) UserId on the dependent entity Text, just to make happy EF. Finally found that you can replace the primary key used in the relationship (UserId)
using HasPrincipalKey()
modelBuilder.Entity<User>()
.HasMany(t => t.Texts)
.WithOne()
.HasPrincipalKey(u => u.Text);
Firstly, change your Model naming please,
public class Text
{
public long Id { get; set; }
public int UserId { get; set; }// add a foreign key that could point to User.Id
public string Body { get; set; }//you cannot have a string property called "Text".
public virtual User Owner { get; set; }
}
public class User
{
public int Id { get; set; }
public virtual ICollection<Text> Texts { get; set; } = new HashSet<Text>();
}
builder.Entity<Text>(table =>
{
table.HasKey(x => x.Id);
table.HasOne(x => x.User)
.WithMany(x => x.Texts)
.HasForeignKey(x => x.UserId)
.HasPrincipalKey(x => x.Id)//<<== here is core code to let foreign key userId point to User.Id.
.OnDelete(DeleteBehavior.Cascade);
});
the reason we have to figure out which key is referred is because of multiple primary keys. I saw it once in MSDN, but cannot find it back.
You can use shadow properties for foreign keys, it looks popular now.
public class Text
{
public long Id { get; set; }
public string Body { get; set; }
public virtual User Owner { get; set; }
}
public class User
{
public int Id { get; set; }
public virtual ICollection<Text> Texts { get; set; } = new HashSet<Text>();
}
builder.Entity<Text>(table =>
{
table.HasKey(x => x.Id);
// Add the shadow property to the model
table.Property<int>("UserId");
table.HasOne(x => x.User)
.WithMany(x => x.Texts)
.HasForeignKey("UserId")//<<== Use shadow property
.HasPrincipalKey(x => x.Id)//<<==point to User.Id.
.OnDelete(DeleteBehavior.Cascade);
});
In the EF context configuration, specifically in the HasForeignKey() you are supposed to specify Which property on the Text model should be the foreign key that points to the User model?
Since User model's primary key is an int, the foreign key pointing from Text to User should naturally also be an int.
I think the mistake you've made is that you are configuring the PK of Textto also be the FK for the relationship Text -> User. Try to change your Text model to :
public class Text
{
public long Id { get; set; }
public string Text{ get; set; }
public int UserId { get; set; }
}
And your configuration to:
e.HasMany(o => o.Texts).WithOne().HasForeignKey(d => d.UserId).IsRequired();
You can simply drop all the migrations or the migration that made that Id, drop the database (if it is small or has no data) and add a clean migration
I was facing the same issue in one-to-one relationship. If you are facing the issue in one-one relationship. Then try this:
public partial class document
{
public document()
{
groups = new group();
}
public int? group_id { get; set; }
public virtual group groups { get; set; }
}
[Table("group")]
public class group
{
[Key]
[Column("group_id")]
public int group_id { get; set; }
[ForeignKey(nameof(group_id))]
public virtual document document { get; set; }
}
Each document has single group. So, we can consider these settings.
modelBuilder.Entity<group>().HasOne(a => a.document)
.WithOne(y => y.groups).HasForeignKey<document>(b => b.group_id);

Categories

Resources