C
C#8mo ago
FoxySnake

Foreign Key between Models with ef

Hi, I have an API in .net and I'm trying to link the property PackageTebexId from the model UserPackage to the property TebexId from the model Package but I can't achieve to do it. It always bind PackageTebexId to the Id of the model Package. Here's my models : User.cs
public class User : EntityBase
{
public List<UserPackage> Packages { get; set; } = new List<UserPackage>();
}
public class User : EntityBase
{
public List<UserPackage> Packages { get; set; } = new List<UserPackage>();
}
UserPackage.cs
public class UserPackage : EntityBase
{
public int UserId { get; set; }

public User User { get; set; }

public long PackageTebexId { get; set; }

public Package Package { get; set; }

public int Quantity { get; set; }
}
public class UserPackage : EntityBase
{
public int UserId { get; set; }

public User User { get; set; }

public long PackageTebexId { get; set; }

public Package Package { get; set; }

public int Quantity { get; set; }
}
Package.cs
public class Package : EntityBase
{
public long TebexId { get; set; }

public string Name { get; set; }

public string? ImageUrl { get; set; }

public decimal TotalPrice { get; set; }

public DateTime? ExpirationDate { get; set; }

public DateTime? CreationDate { get; set; }
}
public class Package : EntityBase
{
public long TebexId { get; set; }

public string Name { get; set; }

public string? ImageUrl { get; set; }

public decimal TotalPrice { get; set; }

public DateTime? ExpirationDate { get; set; }

public DateTime? CreationDate { get; set; }
}
EntityBase.cs
public abstract class EntityBase
{
public int Id { get; set; }
}
public abstract class EntityBase
{
public int Id { get; set; }
}
And here's my DbContext NewSkyDbContext.cs
public class NewSkyDbContext : DbContext
{
public NewSkyDbContext(DbContextOptions<NewSkyDbContext> dbContextOptions) : base(dbContextOptions)
{

}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

var modelTypes = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !type.IsAbstract && !type.IsGenericType && type.IsClass && typeof(EntityBase).IsAssignableFrom(type));

foreach (var modelType in modelTypes)
{
modelBuilder.Entity(modelType);
}

// UserPackage
modelBuilder.Entity<UserPackage>()
.HasKey(x => new { x.PackageTebexId, x.UserId });

modelBuilder.Entity<UserPackage>()
.HasOne(x => x.User)
.WithMany(x => x.Packages)
.HasForeignKey(x => x.PackageTebexId);

modelBuilder.Entity<UserPackage>()
.HasOne(x => x.Package)
.WithMany()
.HasForeignKey(x => x.PackageTebexId);

// Package
modelBuilder.Entity<Package>()
.Property(x => x.TotalPrice)
.HasPrecision(12,2);

modelBuilder.Entity<Package>()
.HasIndex(x => x.TebexId)
.IsUnique();

SeedData(modelBuilder);
}

private void SeedData(ModelBuilder modelBuilder)
{

}
}
public class NewSkyDbContext : DbContext
{
public NewSkyDbContext(DbContextOptions<NewSkyDbContext> dbContextOptions) : base(dbContextOptions)
{

}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

var modelTypes = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !type.IsAbstract && !type.IsGenericType && type.IsClass && typeof(EntityBase).IsAssignableFrom(type));

foreach (var modelType in modelTypes)
{
modelBuilder.Entity(modelType);
}

// UserPackage
modelBuilder.Entity<UserPackage>()
.HasKey(x => new { x.PackageTebexId, x.UserId });

modelBuilder.Entity<UserPackage>()
.HasOne(x => x.User)
.WithMany(x => x.Packages)
.HasForeignKey(x => x.PackageTebexId);

modelBuilder.Entity<UserPackage>()
.HasOne(x => x.Package)
.WithMany()
.HasForeignKey(x => x.PackageTebexId);

// Package
modelBuilder.Entity<Package>()
.Property(x => x.TotalPrice)
.HasPrecision(12,2);

modelBuilder.Entity<Package>()
.HasIndex(x => x.TebexId)
.IsUnique();

SeedData(modelBuilder);
}

private void SeedData(ModelBuilder modelBuilder)
{

}
}
8 Replies
Jimmacle
Jimmacle8mo ago
i'm not sure what you're asking makes sense foreign keys point to other entities/rows in another table, not a single piece of information the correct way to do this is simply access UserPackage.Package.TebexId, you don't need to "link" anything else
FoxySnake
FoxySnake8mo ago
what I'm trying to do is to link the table Package to the table UserPackages like that, when I take my User, I can retrieve also their packages. Like this User user = await _userRepository.Query().Include(x => x.Packages).ThenInclude(x => x.Package); It's been a year i didn't touch to a .Net API so maybe my thoughts are wrong.
Jimmacle
Jimmacle8mo ago
all you need for this is the public Package Package { get; set; } in UserPackage you don't even need to configure the relationship manually
FoxySnake
FoxySnake8mo ago
ok ty, will try it
Jimmacle
Jimmacle8mo ago
i don't know what you're trying to do with the tebex id, that seems like a property of a package and not the primary key of any of your entities
FoxySnake
FoxySnake8mo ago
The TebexId is the Id of the package I retrieved of an other application. but I can't set it to the primary key because of the "IDENTITY_INSERT" that are enabled that forgive me to create package with a custom id in my db
Jimmacle
Jimmacle8mo ago
right, foreign keys should be using the primary keys of your entities not random keys you got somewhere else
FoxySnake
FoxySnake8mo ago
ok mb ok i change a bit the logic like you said and it work well, ty
Want results from more Discord servers?
Add your server