How to map a unidirectional many-to-one relationship? - c#

I have an Item entity:
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public string Skuid { get; set; }
public double Price { get; set; }
public double Amount { get; set; }
}
And an Order entity:
public class Order
{
public long Id { get; set; }
public DateTime Date { get; set; }
public StatusEnum Status { get; set; }
public long SellerId { get; set; }
public Seller Seller { get; set; }
public double Total { get; set; }
public IList<Item> Items { get; set; }
}
My objective is to save the Order containing the items in the Database, but when the request is made, only the reference of my entity "Seller" is saved, but not the references of the items.
I did the following mapping on the "Order" entity:
public class OrderMap : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.ToTable("Orders");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.ValueGeneratedOnAdd()
.UseIdentityColumn();
builder.Property(x => x.Date)
.IsRequired()
.HasColumnName("DateSale")
.HasColumnType("DATETIME")
.HasDefaultValueSql("GETDATE()");
builder.Property(x => x.Total)
.IsRequired()
.HasColumnName("Total")
.HasColumnType("DECIMAL");
builder.Property(x => x.Status)
.IsRequired()
.HasConversion(
v => v.ToString(),
v => (StatusEnum)Enum.Parse(typeof(StatusEnum), v))
.HasColumnName("Status")
.HasColumnType("NVARCHAR") //verificar se nao vai dar conflito
.HasMaxLength(120);
builder
.HasOne(x => x.Seller)
.WithOne()
.HasConstraintName("FK_Seller_Order")
.OnDelete(DeleteBehavior.Cascade);
builder
.HasMany(x => x.Items)
.WithOne()
.HasConstraintName("FK_Item_Order")
.IsRequired()
.OnDelete(DeleteBehavior.Cascade); //
}
}
What is the correct mapping to do?

Please first add these properties OrderId and Order to your Item entity class. This way you are instructions the framework to create an OrderId foreign key
column in the database.
public class Item
{
public long Id { get; set; }
public string Name { get; set; }
public string Skuid { get; set; }
public double Price { get; set; }
public double Amount { get; set; }
public long OrderId { get; set; }
public Order Order {get; set; }
}
And perhaps this part
builder.HasMany(x => x.Items).WithOne()
should be like this
builder.HasMany(x => x.Items).WithOne(x => x.Order)

Related

Entity Framework getting Branches table throws an exception from the type Microsoft.Data.SqlClient.SqlException I don't know why

I'm using entity framework in ASP.NET Core Web API project
I have built the model using the scaffold command from the package manager console and everything is working properly, I can edit the tables, I can insert data, I can update, get lists of data using many different criteria.
any ways my problem is when I try to get all the data from a table named 'Branches'
I get an error of type Microsoft.Data.SqlClient.SqlException with a message says "Invalid column name 'UserIndx'."
this is my code that tries to get the data
/// <summary>
/// Function that returns a list with all the branch table data.
/// </summary>
public List<Branch> getBranches()
{
List<Branch> list = new List<Branch>();
try
{
list = db.Branches.ToList();
return list;
}
catch(Exception ex)
{
er.writeToErrorLog("BLDataEntry", "Branches", "getBranches", ex);
return list;
}
}
This is my branch class that was auto generated by the scaffold command
public partial class Branch
{
public int Indx { get; set; }
public string Branch1 { get; set; } = null!;
public string? IataNo { get; set; }
public int? VatDealer { get; set; }
public string? Tel { get; set; }
public string? Tel2 { get; set; }
public string? Fax { get; set; }
public string? Fax2 { get; set; }
public string? Address { get; set; }
public int? SagentId { get; set; }
public int? OutAccGroup { get; set; }
public int? IntAccGroup { get; set; }
public int? IncAccGroup { get; set; }
public int? IspAccGroup { get; set; }
public byte[]? RptLogo { get; set; }
public byte[]? AppLogo { get; set; }
public int? Company { get; set; }
public DateTime OpenDate { get; set; }
public bool SellOnly { get; set; }
public bool? IsOblClientDetails { get; set; }
public DateTime? CloseDate { get; set; }
public string? LocalName { get; set; }
public string? LocalAddress { get; set; }
public string? Longitude { get; set; }
public string? Latitude { get; set; }
public string? WorkingDaysHours { get; set; }
public string? Iban { get; set; }
public string? KvKnr { get; set; }
public string? Btwnr { get; set; }
public string? Biccode { get; set; }
public byte[]? AddLogos { get; set; }
public string? Email { get; set; }
public string? WebSite { get; set; }
public virtual ICollection<AccBank> AccBanks { get; } = new List<AccBank>();
public virtual ICollection<Agent> Agents { get; } = new List<Agent>();
public virtual ICollection<Department> Departments { get; } = new List<Department>();
public virtual ICollection<SpecialProductDistribution> SpecialProductDistributions { get; } = new List<SpecialProductDistribution>();
}
This is the code from the dbContext.cs that also was auto generated by the scaffold command by entity framework
modelBuilder.Entity<Branch>(entity =>
{
entity.HasKey(e => e.Indx);
entity.Property(e => e.AddLogos).HasColumnType("image");
entity.Property(e => e.Address).HasMaxLength(50);
entity.Property(e => e.AppLogo).HasColumnType("image");
entity.Property(e => e.Biccode)
.HasMaxLength(10)
.HasColumnName("BICcode");
entity.Property(e => e.Branch1)
.HasMaxLength(50)
.HasColumnName("Branch");
entity.Property(e => e.Btwnr)
.HasMaxLength(15)
.HasColumnName("BTWnr");
entity.Property(e => e.CloseDate).HasColumnType("datetime");
entity.Property(e => e.Email).HasMaxLength(100);
entity.Property(e => e.Fax).HasMaxLength(15);
entity.Property(e => e.Fax2).HasMaxLength(15);
entity.Property(e => e.IataNo).HasMaxLength(12);
entity.Property(e => e.Iban)
.HasMaxLength(50)
.HasColumnName("IBAN");
entity.Property(e => e.IsOblClientDetails)
.IsRequired()
.HasDefaultValueSql("((1))");
entity.Property(e => e.KvKnr)
.HasMaxLength(15)
.HasColumnName("KvKNr");
entity.Property(e => e.Latitude)
.HasMaxLength(15)
.HasColumnName("latitude");
entity.Property(e => e.LocalAddress).HasMaxLength(100);
entity.Property(e => e.LocalName).HasMaxLength(100);
entity.Property(e => e.Longitude)
.HasMaxLength(15)
.HasColumnName("longitude");
entity.Property(e => e.OpenDate)
.HasDefaultValueSql("(getdate())")
.HasColumnType("datetime");
entity.Property(e => e.RptLogo).HasColumnType("image");
entity.Property(e => e.SagentId).HasColumnName("SAgentID");
entity.Property(e => e.Tel).HasMaxLength(15);
entity.Property(e => e.Tel2).HasMaxLength(15);
entity.Property(e => e.WebSite).HasMaxLength(100);
entity.Property(e => e.WorkingDaysHours).HasMaxLength(255);
});
I have searched the whole project for a column with the name UserIndx and it doesn't exist in my whole solution I have tried to pull a specific column from that table and it worked right as it should
the problem is basically when I wanna grab all the table into a list.
I have tried getting back data when I asked for specific columns.

Table creation failing with Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints

I have a series of tables that I'm trying to create in Entity Framework that are failing on create.
The exact error:
Introducing FOREIGN KEY constraint 'FK_Units_Customers_CustomerId' on
table 'Units' 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 or index. See previous
errors.
My tables are:
Customer
Account (A customer can have many accounts, an account must have a
customer)
Category (A customer can have many categories, a category must have a
customer)
Transaction (An account can have many transactions, but a transaction can only have a single account)
Unit (This is the table that will be queries most often. A Unit MUST have a single transaction, and MAY have a single category. Units are also linked to customers so I can easily query all the units for a specific customer
Code:
modelBuilder.Entity<Customer>()
.HasMany(x => x.Accounts)
.WithOne(x => x.Customer)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Customer>()
.HasMany(e => e.Categories)
.WithOne(x => x.Customer)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Account>()
.HasMany(x => x.Transactions)
.WithOne(x => x.Account)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Unit>()
.HasOne(x => x.Customer)
.WithMany(x => x.Units)
.HasForeignKey(x => x.CustomerId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Unit>()
.HasOne(x => x.Transaction)
.WithMany(x => x.Units)
.HasForeignKey(x => x.TransactionId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Unit>()
.HasOne(x => x.Category)
.WithMany(x => x.Units)
.HasForeignKey(x => x.CategoryId)
.OnDelete(DeleteBehavior.Cascade);
}
Customer model:
public class Customer
{
public Customer()
{
Accounts = new List<Account>();
Categories = new List<Category>();
Units = new List<Unit>();
}
[Key]
public Guid CustomerId { get; set; }
public List<Account> Accounts { get; set; }
public List<Category> Categories { get; set; }
public List<Unit> Units { get; set; }
}
Account model
public class Account
{
[Key]
public Guid AccountId { get; set; }
[Required]
public Guid CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customer Customer { get; set; }
public List<Transaction> Transactions { get; set; }
}
Transaction model:
public class Transaction
{
public Transaction()
{
Units = new List<Unit>();
}
[Key]
public Guid TransactionId { get; set; }
[Required]
public Guid AccountId { get; set; }
[ForeignKey("AccountId")]
public virtual Account Account { get; set; }
public List<Unit> Units { get; set; }
}
Unit model:
public class Unit
{
[Key]
public int UnitId { get; set; }
[Required]
public Guid CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customer Customer { get; set; }
[Required]
public Guid TransactionId { get; set; }
[ForeignKey("TransactionId")]
public virtual Transaction Transaction { get; set; }
public Guid CategoryId { get; set; }
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
public decimal Amount { get; set; }
}
Category model
public class Category
{
public Category()
{
Units = new List<Unit>();
}
[Key]
public Guid CategoryId { get; set; }
[Required]
public Guid CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customer Customer { get; set; }
public List<Unit> Units { get; set; }
}

EF Core dont full reference between models

My entities classes that are used in the project:
public class Game
{
public int Id { get; set; }
public int FirstTeamId { get; set; }
public Team FirstTeam { get; set; }
public int SecondTeamId { get; set; }
public Team SecondTeam { get; set; }
public Stadium Stadium { get; set; }
public DateTime Date { get; set; }
public GameStatus Result { get; set; }
public Game(DateTime date , GameStatus result )
{
Date = date;
Result = result;
}
}
public class Player
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime Birthday { get; set; }
public PlayerStatus Status { get; set; }
public PlayerHealthStatus HealthStatus { get; set; }
public int Salary { get; set; }
public int TeamId { get; set; }
public Team Team { get; set; }
public Player(string name , string surname, DateTime birthday, PlayerStatus status, PlayerHealthStatus healthStatus, int salary)
{
Name = name;
Surname = surname;
Birthday = birthday;
Status = status;
HealthStatus = healthStatus;
Salary = salary;
}
}
public class Stadium
{
public int Id { get; set; }
public string Name { get; set; }
public int Capacity { get; set; }
public int PriceForPlace { get; set; }
public Stadium(string name, int capacity, int priceForPlace)
{
Name = name;
Capacity = capacity;
PriceForPlace = priceForPlace;
}
}
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public List<Player> Players { get; set; }
public List<Game> Games { get; set; }
public Team(string name)
{
Name = name;
}
public Team(string name, List<Player> players) : this(name)
{
Players = players;
}
}
My EF Core context class:
public class ApplicationContext : DbContext
{
public DbSet<Player> Players { get; set; }
public DbSet<Game> Games { get; set; }
public DbSet<Team> Teams { get; set; }
public DbSet<Stadium> Stadiums { get; set; }
public ApplicationContext()
{
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=best-komp;Database=FootballApplicationDataBase;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Player>()
.HasOne(p => p.Team)
.WithMany(t => t.Players)
.HasForeignKey(p => p.TeamId).OnDelete(DeleteBehavior.NoAction)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Team>()
.HasMany(t => t.Players)
.WithOne(p => p.Team)
.HasForeignKey(p => p.Id).OnDelete(DeleteBehavior.NoAction)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Game>()
.HasOne(g => g.HomeTeam)
.WithMany(t => t.HomeGames)
.HasForeignKey(t => t.HomeTeamId)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Game>()
.HasOne(g => g.AwayTeam)
.WithMany(t => t.AwayGames)
.HasForeignKey(t => t.AwayTeamId).OnDelete(DeleteBehavior.NoAction)
.HasPrincipalKey(t => t.Id);
}
}
But when I try to call my context class, like
var db = new ApplicationContext();
I can see that my team and player classes dont refer to each other.
All other classes have refer to team, like player have a team, game have a team. But my team classes dont have refer to any class, they have NULL instead a reference.
What is the problem?
Your Team configuration is incorrect. The foreign key should be TeamId not Id. As the FK on Players entity is TeamId.
modelBuilder.Entity<Team>()
.HasMany(t => t.Players)
.WithOne(p => p.Team)
.HasForeignKey(p => p.TeamId).OnDelete(DeleteBehavior.NoAction)
.HasPrincipalKey(t => t.Id);
Maybe try using ForeignKey annotations. First, add using statement:
using System.ComponentModel.DataAnnotations.Schema;
Then add a [ForeignKey("ModelName")] annotation above each foreign key. For example:
[ForeignKey("FirstTeam")]
public int FirstTeamId { get; set; }
public Team FirstTeam { get; set; }
[ForeignKey("SecondTeam")]
public int SecondTeamId { get; set; }
public Team SecondTeam { get; set; }
This makes foreign key relationships explicit that EF sometimes can't infer.

EF models. Navigation properties can only participate in a single relationship

I have my entities like this, they are closely linked.
public class Game
{
public int Id { get; set; }
public int FirstTeamId { get; set; }
public Team FirstTeam { get; set; }
public int SecondTeamId { get; set; }
public Team SecondTeam { get; set; }
public Stadium Stadium { get; set; }
public DateTime Date { get; set; }
public GameStatus Result { get; set; }
public Game(DateTime date , GameStatus result )
{
Date = date;
Result = result;
}
}
public class Player
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime Birthday { get; set; }
public PlayerStatus Status { get; set; }
public PlayerHealthStatus HealthStatus { get; set; }
public int Salary { get; set; }
public int TeamId { get; set; }
public Team Team { get; set; }
public Player(string name , string surname, DateTime birthday, PlayerStatus status, PlayerHealthStatus healthStatus, int salary)
{
Name = name;
Surname = surname;
Birthday = birthday;
Status = status;
HealthStatus = healthStatus;
Salary = salary;
}
}
public class Stadium
{
public int Id { get; set; }
public string Name { get; set; }
public int Capacity { get; set; }
public int PriceForPlace { get; set; }
public Stadium(string name, int capacity, int priceForPlace)
{
Name = name;
Capacity = capacity;
PriceForPlace = priceForPlace;
}
}
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public List<Player> Players { get; set; }
public List<Game> Games { get; set; }
public Team(string name)
{
Name = name;
}
public Team(string name, List<Player> players) : this(name)
{
Players = players;
}
}
In my Context class I'm tried to describe my relationships between classes. But something isn't correct.
public class ApplicationContext : DbContext
{
public DbSet<Player> Players { get; set; }
public DbSet<Game> Games { get; set; }
public DbSet<Team> Teams { get; set; }
public DbSet<Stadium> Stadiums { get; set; }
public ApplicationContext()
{
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=best-komp;Database=FootballApplicationDataBase;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Player>()
.HasOne(p => p.Team)
.WithMany(t => t.Players)
.HasForeignKey(p => p.TeamId)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Team>()
.HasMany(p => p.Players)
.WithOne(p => p.Team)
.HasForeignKey(p => p.TeamId)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Game>()
.HasOne(g => g.FirstTeam)
.WithMany(t => t.Games)
.HasForeignKey(t => t.FirstTeamId)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Game>()
.HasOne(g => g.SecondTeam)
.WithMany(t => t.Games)
.HasForeignKey(t => t.SecondTeamId)
.HasPrincipalKey(t => t.Id);
}
}
What wrong with this code? Because I have "Navigation properties can only participate in a single relationship." error when I try to do something with my ApplicationContext.
You can't reuse Team.Games as the inverse property for both Game.FirstTeam and Team.SecondTeam. Think of it, if you add game to Team.Games, how would EF know which team it is, first or second?
You need two collections to describe the relationships. And that's also a chance to add some more meaning to the class model. For example (only modified code):
public class Game
{
...
public int HomeTeamId { get; set; }
public Team HomeTeam { get; set; }
public int AwayTeamId { get; set; }
public Team AwayTeam { get; set; }
}
public class Team
{
...
public List<Game> HomeGames { get; set; }
public List<Game> AwayGames { get; set; }
}
For a team it's meaningful to make a distinction between home and away games, for example to compare results in both types of games.
And the mapping:
modelBuilder.Entity<Game>()
.HasOne(g => g.HomeTeam)
.WithMany(t => t.HomeGames)
.HasForeignKey(t => t.HomeTeamId)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Game>()
.HasOne(g => g.AwayTeam)
.WithMany(t => t.AwayGames)
.HasForeignKey(t => t.AwayTeamId).OnDelete(DeleteBehavior.NoAction)
.HasPrincipalKey(t => t.Id);
If using Sql Server, this delete behavior instruction is necessary to prevent disallowed multiple cascade paths.
The problem is that your Team model has 2 one-to-many relationships with your Game model but you only have one navigation property on the Team.
You need to have 2 navigation properties on the Team model, one for each relationship.
(Game1, Game2...).
You will also need to define these relationships in the Game model - a Team property for each relationship.
Check this answer for extra info.

Entity Framework core: Invalid column name

I have this database model:
public partial class Image
{
public Image()
{
EntityImages = new List<EntityImage>();
}
public int Id { get; set; }
public string Content { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public string ModifiedBy { get; set; }
public DateTime? ModifiedDate { get; set; }
public bool IsDeleted { get; set; }
public ICollection<EntityImage> EntityImages { get; set; }
}
public partial class EntityImage
{
public int Id { get; set; }
public int ImageId { get; set; }
public int EntityId { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public string ModifiedBy { get; set; }
public DateTime? ModifiedDate { get; set; }
public bool IsDeleted { get; set; }
[ForeignKey("EntityId")]
public Entity Entity { get; set; }
[ForeignKey("ImageId")]
public Image Image { get; set; }
}
I used database first, and when I am trying to make an insert into Images tables, I got the "Invalid column name: EntityId" error.
This is the context code:
modelBuilder.Entity<EntityImage>(entity =>
{
entity.Property(e => e.CreatedBy).HasMaxLength(50);
entity.Property(e => e.CreatedDate).HasColumnType("datetime");
entity.Property(e => e.ModifiedBy).HasMaxLength(50);
entity.Property(e => e.ModifiedDate).HasColumnType("datetime");
entity.HasOne(d => d.Entity)
.WithMany(p => p.EntityImages)
.HasForeignKey(d => d.EntityId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_CategorySubcategory_Entities");
entity.HasOne(d => d.Image)
.WithMany(p => p.EntityImages)
.HasForeignKey(d => d.ImageId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_CategorySubcategory_Images");
});
modelBuilder.Entity<Image>(entity =>
{
entity.Property(e => e.Content)
.IsRequired()
.HasMaxLength(50);
entity.Property(e => e.CreatedBy).HasMaxLength(50);
entity.Property(e => e.CreatedDate).HasColumnType("datetime");
entity.Property(e => e.ModifiedBy).HasMaxLength(50);
entity.Property(e => e.ModifiedDate).HasColumnType("datetime");
});
I do not know where the error is.
I do not know why Entity Framework try to insert a image record with a EntityId column since it columns does not exists in that table.
I have the same model for categories, subcategories and categoriesSubcategories tables and the code work without any problems.

Categories

Resources