c# Entity framework foreign key - entity-framework

I'm new here and hope I'll get an answer - I'm searching the internet since two days ...
It's the first time I use the entity framewort in a Windows 10 UWP. I have to classes which are the objects for my database. In one object I use a property with the type of the other.
If I'll try to add a record I'll get a error.
public class budgetcontext : DbContext
{
private string myDB = "Filename=budget_4.db";
public DbSet<category> Categories { get; set; }
public DbSet<transaction> Transactions { get; set; }
public budgetcontext()
{
this.Database.Migrate();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(myDB);
}
}
public class category
{
private string myGuid = Guid.NewGuid().ToString();
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CategoryId { get; set; }
public string Name { get; set; }
public double BudgetDaily { get; set; }
public double BudgetWeekly { get; set; }
public double BudgetMonthly { get; set; }
public double BudgetYearly { get; set; }
public string CategoryGuid
{
get
{
return myGuid;
}
}
}
public class transaction
{
private string myGuid = Guid.NewGuid().ToString();
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int64 TransactionId { get; set; }
public string Text { get; set; }
public category Category { get; set; }
public DateTime TransDateTime { get; set; }
public double Amount { get; set; }
}
If I try to insert a record of the type transaction to the database I'll get the error:
{"SQLite Error 19: 'UNIQUE constraint failed: Categories.CategoryId'."}
The code to insert the object is:
budget_sqlite.category c = cbCategory.SelectedItem as budget_sqlite.category; //Object is selected in a Combo
using (var db = new budget_sqlite.budgetcontext())
{
t.Text = this.txtText.Text;
t.Category = c;
t.TransDateTime = new DateTime(dpDate.Date.Year, dpDate.Date.Month, dpDate.Date.Day, tpTime.Time.Hours, tpTime.Time.Minutes, tpTime.Time.Seconds);
double.TryParse(txtAmount.Text, out value);
if (RBOut.IsChecked == true)
{
value = value * -1;
}
t.Amount = value;
if (t.TransactionId == 0)
{
db.Transactions.Add(t);
}
db.SaveChanges();
}
Here are the migrations:
[DbContext(typeof(budgetcontext))]
partial class budgetcontextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation("ProductVersion", "1.1.0-rtm-22752");
modelBuilder.Entity("budget_sqlite.category", b =>
{
b.Property<int>("CategoryId")
.ValueGeneratedOnAdd();
b.Property<double>("BudgetDaily");
b.Property<double>("BudgetMonthly");
b.Property<double>("BudgetWeekly");
b.Property<double>("BudgetYearly");
b.Property<string>("Name");
b.HasKey("CategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("budget_sqlite.transaction", b =>
{
b.Property<long>("TransactionId")
.ValueGeneratedOnAdd();
b.Property<double>("Amount");
b.Property<int?>("CategoryId");
b.Property<string>("Text");
b.Property<DateTime>("TransDateTime");
b.HasKey("TransactionId");
b.HasIndex("CategoryId");
b.ToTable("Transactions");
});
modelBuilder.Entity("budget_sqlite.transaction", b =>
{
b.HasOne("budget_sqlite.category", "Category")
.WithMany()
.HasForeignKey("CategoryId");
});
}
}
public partial class V0001 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Categories",
columns: table => new
{
CategoryId = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
BudgetDaily = table.Column<double>(nullable: false),
BudgetMonthly = table.Column<double>(nullable: false),
BudgetWeekly = table.Column<double>(nullable: false),
BudgetYearly = table.Column<double>(nullable: false),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Categories", x => x.CategoryId);
});
migrationBuilder.CreateTable(
name: "Transactions",
columns: table => new
{
TransactionId = table.Column<long>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Amount = table.Column<double>(nullable: false),
CategoryId = table.Column<int>(nullable: true),
Text = table.Column<string>(nullable: true),
TransDateTime = table.Column<DateTime>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Transactions", x => x.TransactionId);
table.ForeignKey(
name: "FK_Transactions_Categories_CategoryId",
column: x => x.CategoryId,
principalTable: "Categories",
principalColumn: "CategoryId",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_Transactions_CategoryId",
table: "Transactions",
column: "CategoryId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Transactions");
migrationBuilder.DropTable(
name: "Categories");
}
}
Thank you very much for your help.

Related

How to insert payload data in many-to-many relationships with EF Core 5

I have this relationship between Licitadores and Ofertas
public class Licitador
{
public int Id { get; set; }
public string Nombre { get; set; }
[StringLength(maximumLength: 15)]
public string CodigoSAP { get; set; }
public List<Oferta> Ofertas { get; set; } = new List<Oferta>();
}
public class Oferta
{
[StringLength(maximumLength:6)]
public string Id { get; set; }
[StringLength(maximumLength: 5)]
public string IdPresentada { get; set; }
....
public List<Licitador> Licitadores { get; set; } = new List<Licitador>();
}
And the join table in the context
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<LicitacionesEnSolitario>().ToTable("LicitacionesSolitario");
modelBuilder.Entity<Licitador>()
.HasMany(o => o.Ofertas)
.WithMany(of => of.Licitadores)
.UsingEntity<LicitacionesEnSolitario>
(oo => oo.HasOne<Oferta>().WithMany(),
oo => oo.HasOne<Licitador>().WithMany())
.Property(oo => oo.Adjudicado)
.IsRequired();
}
I need this data in my entity/table LicitacionesEnSolitario in addition to PK y FK
public class LicitacionesEnSolitario
{
public int LicitadorId { get; set; }
public string OfertaId { get; set; }
public bool Adjudicado { get; set; }
public string Plazo { get; set; }
public decimal PresupuestoOfertado { get; set; }
public DateTime? FechaAdjudicacion { get; set; }
}
Here I insert the data importing them from another database
public int ImportarLicitacionesEnSolitario()
{
try
{
int registrosAñadidos = 0;
var registrosSAP = _contextSAP.LicitacionesEnSolitario
.FromSqlRaw("sql")
.ToList();
foreach (var registroSAP in registrosSAP)
{
var oferta = _contextBoletus.Ofertas.Find(registroSAP.OfertaId);
var licitador = _contextBoletus.Licitadores.Where(l => l.CodigoSAP == registroSAP.CodigoSAP).FirstOrDefault();
oferta.Licitadores.Add(licitador);
registrosAñadidos +=1;
}
_contextBoletus.SaveChanges();
return registrosAñadidos;
}
catch (Exception ex)
{
throw ex;
}
}
This works fine and insert data in "LicitacionesEnSolitario" but with this fields Adjudicado, Plazo, PresupuestoPfertado y FechaAdjudicacion with nulls.
I don't know how to insert them at the time I insert Licitadores and if I try to update after the Add method using the PKs I just added
foreach (var registroSAP in registrosSAP)
{
var oferta = _contextBoletus.Ofertas.Find(registroSAP.OfertaId);
var licitador = _contextBoletus.Licitadores.Where(l => l.CodigoSAP == registroSAP.CodigoSAP).FirstOrDefault();
oferta.Licitadores.Add(licitador);
var ls = _contextBoletus.Set<LicitacionesEnSolitario>()
.SingleOrDefault(ls => ls.OfertaId == oferta.Id & ls.LicitadorId == licitador.Id);
ls.Adjudicado = registroSAP.Adjudicado;
ls.PresupuestoOfertado = registroSAP.PresupuestoOfertado;
ls.FechaAdjudicacion = registroSAP.FechaAdjudicacion;
registrosAñadidos +=1;
}
_contextBoletus.SaveChanges();
return registrosAñadidos;
I get this error System.NullReferenceException: Object reference not set to an instance of an object.
Any idea, please?
Thanks
This is the best way I found
foreach (var registroSAP in registrosSAP)
{
var oferta = _contextBoletus.Ofertas.Find(registroSAP.OfertaId);
var licitador = _contextBoletus.Licitadores.Where(l => l.CodigoSAP == registroSAP.CodigoSAP).FirstOrDefault();
var ls = _contextBoletus.Set<LicitacionesEnSolitario>().Add(
new LicitacionesEnSolitario
{
LicitadorId = licitador.Id,
OfertaId = oferta.Id,
Adjudicado = registroSAP.Adjudicado,
Plazo = registroSAP.Plazo,
PresupuestoOfertado = registroSAP.PresupuestoOfertado,
FechaAdjudicacion = registroSAP.FechaAdjudicacion
});
registrosAñadidos += 1;
}
Thanks

Many to Many relationship Entity Framework Core 5

I created a Blazor project and I have a many-to-many relationship between these classes:
public class ItemAttribute
{
[Key]
public int ItemAttributeId { get; set; }
public string Title { get; set; }
public ICollection<Item> Items { get; set; }
public ICollection<ItemAttributeCluster> itemAttributeClusters { get; set; }
}
and
public class ItemAttributeCluster
{
[Key]
public int ItemAttributeClusterId { get; set; }
public string Titel { get; set; }
public bool IsMultiChoice { get; set; }
public ICollection<ItemAttribute> itemAttributes { get; set; }
}
So far so good, EF generates the Join table ItemAttributeItemAttributeCluster, ok.
Then I try to add a new cluster of ItemAttributes for the first time with my controller:
// Create
[HttpPost]
public async Task<IActionResult> Post(ItemAttributeCluster itemAttributeCluster)
{
_context.ItemAttributeClusters.Add(itemAttributeCluster);
await _context.SaveChangesAsync();
return Ok(itemAttributeCluster);
}
and I get this error:
Cannot insert explicit value for identity column in table 'ItemAttributes' when IDENTITY_INSERT is set to OFF.
What am I doing wrong? Why is EF trying to write something into 'ItemAttributes'? When i´m trying to create a new Cluster on 'ItemAttributesCluster' and the Join Table?
Migration Builder:
Join Table
migrationBuilder.CreateTable(
name: "ItemAttributeItemAttributeCluster",
columns: table => new
{
itemAttributeClustersItemAttributeClusterId = table.Column<int>(type: "int", nullable: false),
itemAttributesItemAttributeId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ItemAttributeItemAttributeCluster", x => new { x.itemAttributeClustersItemAttributeClusterId, x.itemAttributesItemAttributeId });
table.ForeignKey(
name: "FK_ItemAttributeItemAttributeCluster_ItemAttributeClusters_itemAttributeClustersItemAttributeClusterId",
column: x => x.itemAttributeClustersItemAttributeClusterId,
principalTable: "ItemAttributeClusters",
principalColumn: "ItemAttributeClusterId",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ItemAttributeItemAttributeCluster_ItemAttributes_itemAttributesItemAttributeId",
column: x => x.itemAttributesItemAttributeId,
principalTable: "ItemAttributes",
principalColumn: "ItemAttributeId",
onDelete: ReferentialAction.Cascade);
});
ItemAttributes
migrationBuilder.CreateTable(
name: "ItemAttributes",
columns: table => new
{
ItemAttributeId = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ItemAttributes", x => x.ItemAttributeId);
});
ItemAttributeCluster
migrationBuilder.CreateTable(
name: "ItemAttributeClusters",
columns: table => new
{
ItemAttributeClusterId = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Titel = table.Column<string>(type: "nvarchar(max)", nullable: true),
IsMultiChoice = table.Column<bool>(type: "bit", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ItemAttributeClusters", x => x.ItemAttributeClusterId);
});
If this was an existing schema for the ItemAttribute / Cluster tables and their PK were defined as identity columns, you will need to tell EF to expect them using the [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute alongside the Key designation.
When using a naming convention that EF recognizes like "ItemAttributeId" or "Id" I believe EF will default to assuming these are Identity columns, but with a name like "ItemAttributeCode" I believe it would assume a database generated option of "None" as default.
try to add some navigation properties
public ItemAttributeCluster()
{
AttributeClusters = new HashSet<AttributeCluster>();
}
[Key]
public int Id { get; set; }
public string Titel { get; set; }
public bool IsMultiChoice { get; set; }
[InverseProperty(nameof(AttributeCluster.ItemAttributeClaster))]
public virtual ICollection<AttributeCluster> AttributeClusters { get; set; }
}
public partial class ItemAttribute
{
public ItemAttribute()
{
AttributeClusters = new HashSet<AttributeCluster>();
}
[Key]
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Item> Items { get; set; }
[InverseProperty(nameof(AttributeCluster.ItemAttribute))]
public virtual ICollection<AttributeCluster> AttributeClusters { get; set; }
}
public partial class AttributeCluster
{
[Key]
public int Id { get; set; }
public int ItemAttributeId { get; set; }
public int ItemAttributeClasterId { get; set; }
[ForeignKey(nameof(ItemAttributeId))]
[InverseProperty("AttributeClusters")]
public virtual ItemAttribute ItemAttribute { get; set; }
[ForeignKey(nameof(ItemAttributeClasterId))]
[InverseProperty(nameof(ItemAttributeCluster.AttributeClusters))]
public virtual ItemAttributeCluster ItemAttributeClaster { get; set;
}
dbcontext (no any fluent apis at all)
public virtual DbSet<AttributeCluster> AttributeClusters { get; set; }
public virtual DbSet<ItemAttribute> ItemAttributes { get; set; }
public virtual DbSet<ItemAttributeCluster> ItemAttributeClusters { get; set; }
Test
var itemAttributeClaster = new ItemAttributeCluster { Titel="titleClaster2", IsMultiChoice=false};
var itemAttribute = new ItemAttribute{Title="attrTitle" };
var attributeClaster = new AttributeCluster { ItemAttribute = itemAttribute, ItemAttributeClaster = itemAttributeClaster };
_context.AttributeClusters.Add(attributeClaster);
_context.SaveChanges();
it created 1 record in each of 3 tables
I give up on getting this to work with ef. I run several sql`s directly to achieve the same functionality and so far it works, not a satisfactory solution but it needs to be done.

Introducing FOREIGN KEY constraint - Basic Migration

I tried to make some project in C# with entity framework core 2.1. However, there is a problem that I can't solve, since I don't see anything wrong.
I'm trying to just do a simple migrate in my database.
There is no problem until I write 'Update-Database' to Package manager console. After trying to update database, here is the error message:
Introducing FOREIGN KEY constraint 'FK_Users_Baskets_BasketId' on table 'Users' 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.
Basket.cs
public class Basket {
[Key]
public int BasketId { get; set; }
public List<ProductByBasket> ProductByBaskets { get; set; }
public string BasketName { get; set; }
public int UserId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; }
}
Product.cs
public class Product {
[Key]
public int ProductId { get; set; }
public List<ProductByBasket> ProductByBaskets { get; set; }
public string ProductName { get; set; }
}
ProductByBasket.cs
[Key]
public int ProductByBasketId { get; set; }
public int BasketId { get; set; }
[ForeignKey("BasketId")]
public Basket Basket { get; set; }
public int ProductId { get; set; }
[ForeignKey("ProductId")]
public Product Product { get; set; }
}
Migration File
migrationBuilder.CreateTable(
name: "ProductByBaskets",
columns: table => new
{
BasketId = table.Column<int>(nullable: false),
ProductId = table.Column<int>(nullable: false),
ProductByBasketId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProductByBaskets", x => new { x.ProductId, x.BasketId });
table.UniqueConstraint("AK_ProductByBaskets_ProductByBasketId", x => x.ProductByBasketId);
table.ForeignKey(
name: "FK_ProductByBaskets_Products_ProductId",
column: x => x.ProductId,
principalTable: "Products",
principalColumn: "ProductId",
onDelete: ReferentialAction.Cascade);
});
ApplicationDbContext.cs
public class ApplicationDbContext : DbContext {
public ApplicationDbContext() { }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
string connectionString = #"Data Source=...\SQLEXPRESS; Initial Catalog = db; Integrated Security=true;";
optionsBuilder.UseSqlServer(connectionString);
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<ProductByBasket>()
.HasOne(u => u.Basket).WithMany(u => u.ProductByBaskets).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<ProductByBasket>()
.HasKey(x => new { x.ProductId, x.BasketId });
modelBuilder.Entity<ProductByBasket>()
.HasOne(pt => pt.Basket)
.WithMany(p => p.ProductByBaskets)
.HasForeignKey(pt => pt.BasketId);
modelBuilder.Entity<ProductByBasket>()
.HasOne(pt => pt.Product)
.WithMany(t => t.ProductByBaskets)
.HasForeignKey(pt => pt.ProductId);
}
public DbSet<Product> Products { get; set; }
public DbSet<Basket> Baskets { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<ProductByBasket> ProductByBaskets { get; set; }
}
I tried to configure migration file to write. Then, it looks like:
migrationBuilder.CreateTable(
name: "ProductByBaskets",
columns: table => new
{
BasketId = table.Column<int>(nullable: false),
ProductId = table.Column<int>(nullable: false),
ProductByBasketId = table.Column<int>(nullable: false).Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
},
constraints: table =>
{
table.PrimaryKey("PK_ProductByBaskets", x => x.ProductByBasketId);
table.ForeignKey(
name: "FK_ProductByBaskets_Baskets_BasketId",
column: x => x.BasketId,
principalTable: "Baskets",
principalColumn: "BasketId",
onDelete: ReferentialAction.Cascade);
table.PrimaryKey("PK_ProductByBaskets", x => new { x.ProductId, x.BasketId });
table.UniqueConstraint("AK_ProductByBaskets_ProductByBasketId", x => x.ProductByBasketId);
table.ForeignKey(
name: "FK_ProductByBaskets_Products_ProductId",
column: x => x.ProductId,
principalTable: "Products",
principalColumn: "ProductId",
onDelete: ReferentialAction.Cascade);
});
Then I get this error:
Foreign key references invalid table.
What am I doing wrong?

Insert value into identity column in Core 2.2

Trying to seed database in MSSQL server. 'Id' column is set to identity. I fail to understand why EF needs data for 'Id:
public class Location
{
public int? Id { get; set; }
public string Name { get; set; }
public IList<Office> Offices { get; set; }
}
... fluent API:
modelBuilder.Entity<Location>()
.HasKey(k => k.Id);
modelBuilder.Entity<Location>()
.Property(p => p.Id)
.UseSqlServerIdentityColumn()
.ValueGeneratedOnAdd();
modelBuilder.Entity<Location>()
.HasData(
new Location() { Name = "Sydney" },
new Location() { Name = "Melbourne" },
new Location() { Name = "Brisbane" }
);
... as far as I understand 'Id' doesn't need to be provided if it's generated by server on insert. Why do I get the messages about not providing Id ...
I think that the error is here
public int? Id { get; set; }
Id should not be nullable.
Update:
What I mean is that you should write:
public int Id { get; set; }
The question mark makes your property nullable, but since it is a primary key it cannot be null.
I did a littel example here:
using System.Collections.Generic;
namespace ConsoleApp2.Models
{
public class Location
{
public int Id { get; set; }
public string Name { get; set; }
public IList<Office> Offices { get; set; }
}
}
Fluent Api
migrationBuilder.CreateTable(
name: "Locations",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Locations", x => x.Id);
});
I can add new location without problems.
using ConsoleApp2.Models;
using System.Collections.Generic;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
MyDbContext _c = new MyDbContext();
List<Office> list = new List<Office>()
{
new Office()
{
OfficeName = "Reception"
}
};
Location l = new Location()
{
Name = "New York",
Offices = list
};
_c.Locations.Add(l);
_c.SaveChanges();
}
}
}
Im using .net core 2.1 with EFcore 2.2.2.
I hope that help.

Entity Framework Required With Optional

I have the following model where I am attempting to make the Notification property on a Request object be null or the id of a notification.
However, I am not quite sure of how to map this with the fluent mapping. HasOptional -> WithMany seems to be the closest I can get, but I'd like to ensure that the NotificationId column in Requests is unique. What is the best way to accomplish this with fluent mapping?
public class Request
{
public int RequestId { get; set; }
public string Description { get; set; }
public int? NotificationId { get; set; }
public virtual Notification Notification { get; set; }
}
public class Notification
{
public int NotificationId { get; set; }
public string Description { get; set; }
public DateTime CreateDate { get; set; }
}
public class RequestMap : EntityTypeConfiguration<Request>
{
public RequestMap()
{
HasKey(x => x.RequestId);
Property(x => x.Description).IsRequired().HasMaxLength(255);
HasOptional(x => x.Notification)
.WithWhat?
}
}
using HasOptional(x => x.Notification) is enough you don't need WithMany
you dont have many Request with the same Notification
public class Request
{
public int RequestID { get; set; }
public string Description { get; set; }
public int? NotificationId { get; set; }
public Notification Notification { get; set; }
}
public class Notification
{
public int NotificationId { get; set; }
public string Description { get; set; }
public DateTime CreateDate { get; set; }
}
public class RequestMap : EntityTypeConfiguration<Request>
{
public RequestMap()
{
HasKey(x => x.RequestID);
Property(x => x.Description).IsRequired().HasMaxLength(255);
HasOptional(x => x.Notification);
}
}
and the generated migration
public partial class initial : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Notifications",
c => new
{
NotificationId = c.Int(nullable: false, identity: true),
Description = c.String(),
CreateDate = c.DateTime(nullable: false),
})
.PrimaryKey(t => t.NotificationId);
CreateTable(
"dbo.Requests",
c => new
{
RequestID = c.Int(nullable: false, identity: true),
Description = c.String(nullable: false, maxLength: 255),
NotificationId = c.Int(),
})
.PrimaryKey(t => t.RequestID)
.ForeignKey("dbo.Notifications", t => t.NotificationId)
.Index(t => t.NotificationId);
}
public override void Down()
{
DropForeignKey("dbo.Requests", "NotificationId", "dbo.Notifications");
DropIndex("dbo.Requests", new[] { "NotificationId" });
DropTable("dbo.Requests");
DropTable("dbo.Notifications");
}
}