ASP EF7 Set column value in migration - asp.net-core

I want to move from autoincrement ids to composite primary keys. So, these two entities
public class SeasonTeam
{
public int SeasonTeamId { get; set; }
public int SeasonId { get; set; }
public int TeamId { get; set; }
}
public class GroupEntry
{
public int GroupEntryId { get; set; }
public int SeasonTeamId { get; set; }
public SeasonTeam SeasonTeam { get; set; }
}
will now look like this
public class SeasonTeam
{
public int SeasonId { get; set; }
public int TeamId { get; set; }
}
public class GroupEntry
{
public int GroupEntryId { get; set; }
public int SeasonId { get; set; }
public int TeamId { get; set; }
public SeasonTeam SeasonTeam { get; set; }
}
Visual Studio generated migration code, but it corrupts data.
migrationBuilder.AddColumn<int>(
name: "SeasonId",
table: "GroupEntry",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "TeamId",
table: "GroupEntry",
nullable: false,
defaultValue: 0);
migrationBuilder.DropForeignKey(name: "FK_GroupEntry_SeasonTeam_SeasonTeamId", table: "GroupEntry");
migrationBuilder.DropPrimaryKey(name: "PK_SeasonTeam", table: "SeasonTeam");
migrationBuilder.DropColumn(name: "SeasonTeamId", table: "SeasonTeam");
Default value 0 obviously won't work, I need ids from referenced SeasonTeam table, but I didn't find any examples. How can I set proper id values for a new composite key before I delete old primary key column?

You can't do this programmatically with EF's APIs, however, if you can write the SQL to move the values from one table to another, you can add a custom migration step after the Add column operations and before the drop column operations.
migrationBuilder.Sql(#"INSERT INTO ...(your SQL here)");
From the limited info in your question, I can't tell you what that SQL should be.

Related

EntityFramework Trying to create multiple links to the same table, FK Constraint error

I have a table called DeliveryRequest and another table called Operator, table DeliveryRequest is as follows:
public class DeliveryRequest
{
public int ID { get; set; }
public DateTime Date { get; set; }
public string UserID { get; set; }
public string Waybill { get; set; }
public string Reference { get; set; }
public int SupplierID { get; set; }
public Supplier Supplier { get; set; }
//[ForeignKey("Operator")]
public int SenderID { get; set; }
public Operator Sender { get; set; }
//[ForeignKey("Operator")]
public int ReceiverID { get; set; }
public Operator Receiver { get; set; }
public string Origin { get; set; }
public string Destination { get; set; }
public int ServiceID { get; set; }
public Service Service { get; set; }
}
And table Operator is as follows:
public class Operator
{
public int ID { get; set; }
public string Company { get; set; }
public int ContactID { get; set; }
public Contact Contact { get; set; }
public int AddressID { get; set; }
public Address Address { get; set; }
}
So the problem is, when I am trying to update my database I get a FK Constraint error as follows:
Introducing FOREIGN KEY constraint
'FK_dbo.DeliveryRequests_dbo.Operators_SenderID' on table
'DeliveryRequests' 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.
And the previous error is the same. As follows:
System.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN
KEY constraint 'FK_dbo.DeliveryRequests_dbo.Operators_SenderID' on
table 'DeliveryRequests' may cause cycles or multiple cascade paths.
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other
FOREIGN KEY constraints.
Focus on the Sender and Receiver part, I am no expert but the error must be there lol
//[ForeignKey("Operator")]
public int SenderID { get; set; }
public Operator Sender { get; set; }
//[ForeignKey("Operator")]
public int ReceiverID { get; set; }
public Operator Receiver { get; set; }
It looks like you are using Code First approach. So try to turn off CascadeDelete for DeliveryRequests:
modelBuilder.Entity<DeliveryRequests>()
.HasRequired(c => c.Operator )
.WithMany()
.WillCascadeOnDelete(false);
For example:
public class YourDBContext: DbContext
{
public YourDBContext(): base()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DeliveryRequests>()
.HasRequired(c => c.Operator )
.WithMany()
.WillCascadeOnDelete(false);
}
}

EF Core Join using Include but ForeignKey is not Primary Key on the other table

I am trying to relate my Tables with ForeignKey and PrimaryKey on the other end. But now i will be using a ForeignKey which is not the primary for the said table. I was using [InverseProperty] but i think there's a bug with it since i've been looking around for hours already and all of them says the same thing about it.
Documents Table:
public class Document
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DocumentId { get; set; }
public int ProjectId { get; set; }
public int DepartmentId { get; set; }
public int AuthorId { get; set; }
[NotMapped]
public virtual User Author { get; set; }
}
Users
public class User
{
[Key]
public int UserId { get; set; }
public int AuthUserId { get; set; }
public string DisplayName { get; set; }
[NotMapped]
[ForeignKey("AuthorId")]
public virtual Document Document { get; set; }
}
Context:
modelBuilder.Entity<User>(entity =>
{
entity.HasOne(u => u.Document)
.WithMany("AuthorId");
});
I am trying to use the solution they here, but no luck.
Any help would really be appreciated. Thanks!
But now i will be using a ForeignKey which is not the primary for the said table.
To do this you can use EF Core Alternate Keys feature. But first correct your model class set up as follows: (As you said a User will have multiple Document)
public class Document
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DocumentId { get; set; }
public int ProjectId { get; set; }
public int DepartmentId { get; set; }
public int AuthorId { get; set; }
public User Author { get; set; }
}
public class User
{
[Key]
public int UserId { get; set; }
public int AuthUserId { get; set; }
public string DisplayName { get; set; }
public ICollection<Document> Documents { get; set; }
}
Then in the Fluent API configuration as follows:
modelBuilder.Entity<Document>()
.HasOne(p => p.Author)
.WithMany(b => b.Documents)
.HasForeignKey(p => p.AuthorId)
.HasPrincipalKey(b => b.AuthUserId); // <-- here you are specifying `AuthUserId` as `PrincipalKey` in the relation which is not primary key

Is it possible to create a Domain Class which has Multiple FK Columns to same PK?

I'm a newbie to designing database.
I have problem how to define a domain class which has multiple foreign keys linked with a same primary key.
Here is my model:
namespace OceanFmsSystem.Domain
{
public class ExportTemplate
{
public int Id { get; set; }
public List<ExportBooking> ExportBookings { get; set; }
public string TemplateName { get; set; }
public int CustomerId { get; set; }
public string Incoterms { get; set; }
public string IncotermsDetail { get; set; }
public string PaymentTerm{ get; set; }
public int CountryOriginId { get; set; }
public int CountryDestinationId { get; set; }
}
}
What I want to do is that CountryOriginId & CountryDestinationId should refer to the below class as foreign keys:
namespace OceanFmsSystem.Domain
{
public class Country
{
public int Id { get; set; }
public string CountryCode { get; set; }
public string CountryName { get; set; }
}
}
As far as I know, in EF Core there is an convention which I should name a foreign key as below for migration from code to database.
public type ClassNameOfPrimaryKeyId { get; set;}
Is there any possible way to make this happens?
Yes, possible. Your class should look like this:
public class ExportTemplate
{
//...
public int CountryOriginId { get; set; }
public Country CountryOrigin { get; set; }
public int CountryDestinationId { get; set; }
public Country CountryDestination { get; set; }
}
EF is smart enough to figure the Ids by convention. If you do not wish to follow the convention you can use [ForeignKey] attribute on the properties to configure the FK:
[ForeignKey("Origin")]
public int MyOriginId { get; set; }
public Country Origin { get; set; }

saving reference using ServiceStack ORMLite

I am using ORMLite as my ORM and I am using it with following structure which contains the foreign key relation ship:
public class Order
{
[AutoIncrement]
public int Id { get; set; }
[Reference]
public Item Item { get; set; }
public string ProUserId { get; set; }
public string Details { get; set; }
}
public class Item
{
[AutoIncrement]
public int Id { get; set; }
public string Description { get; set; }
}
As we can see that Order contains the reference to the Item. In DB Order table has a foreign key called ItemId in the table and I have annotated that key in the design view with [Reference] attribute.
I am trying to save the Order with following code:
var order = new Order
{
Item = new Item
{
Id = 3,
Description = "Something"
},
ProUserId = "kunal#kunal.com",
Details = "fdfsdfsd"
};
Db.Save(order,references:true);
I was hoping that ORMLite would pick up the relationship and with ItemID in the Order table but it did not and it did throw following error instead:
Cannot insert the value NULL into column 'ItemId', table 'WebApp.dbo.Order'; column does not allow nulls. INSERT fails.
I tried changing my schema and addred OrderId column in my Item table with reference there and that works fine. But that is not the correct design. Should I make any changes in my code/schema to support this feature?
You still need to provide the foreign key that OrmLite can use to store the relationship, e.g. either on the Child/ForeignKey table:
public class Order
{
[AutoIncrement]
public int Id { get; set; }
[Reference]
public Item Item { get; set; }
public string ProUserId { get; set; }
public string Details { get; set; }
}
public class Item
{
[AutoIncrement]
public int Id { get; set; }
public int OrderId { get; set; } //Parent Table PK
public string Description { get; set; }
}
Or for 1:1 relationships, can be on the Parent table, e.g:
public class Order
{
[AutoIncrement]
public int Id { get; set; }
[Reference]
public Item Item { get; set; }
public int ItemId { get; set; } //Child Table PK
public string ProUserId { get; set; }
public string Details { get; set; }
}
public class Item
{
[AutoIncrement]
public int Id { get; set; }
public string Description { get; set; }
}

How to build a self referencing table with composite key in fluent api and EF

I'm building a hierarchical Database with "closure table" to build the tree
It is a self referencing table, and the two keys should become the primary key.
The Problem is, I end up with 5 columns, when I expect only 3.
Here is what I tried:
public class Tree
{
public int TaskId { get; set; }
public Task Task { get; set; } //navigation Property to TaskTable
public int? ChildId { get; set; }
public Tree Child { get; set; } //navigation Property
public int Length { get; set; } //Length
}
public class Task
{
public int TaskId { get; set; }
public virtual ICollection<Tree> Trees { get; set; }
}
modelBuilder
.Entity<Task>()
.HasKey(t => t.TaskId);
modelBuilder
.Entity<Tree>()
.HasKey(a => new { a.TaskId, a.ChildId });
The result is a table with 5 columns:
TaskId
ChildId
Length
Child_TaskId
Child_ChildId
I expected:
TaskId
ChildId
Length
I'm guessing some fluent api missing, but I couldn't get to work otherwise ?