Reputation:
I have two tables, JobRequest and WorkOrder. The Primary Key for JobRequest is a varchar field named RequestNumber. There is also a field, of the same name as the foreign key in the work order table. There is a 0 to 1 relationship between the tables on that field; when a job request can't be completed by the organic maintenance team, a work order is issued for another maintenance team.
The databases look a bit like:
JobRequest
ID BIGINT IDENTITY,
RequestNumber VARCHAR(15) NOT NULL,
...
WorkOrder
ID BIGINT IDENTITY,
WONumber VARCHAR(25) NOT NULL,
RequestNumber VARCHAR(15) NULL,
...
I have a model built, the context built and the database tables. I used a manual code first so I don't have any template or SDL files.
My models look like:
[Table("JobRequest")]
public partial class JobRequest
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public JobRequest()
{
AuditLogs = new HashSet<AuditLog>();
AuthorizedUsers = new HashSet<AuthorizedUser>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long? ID { get; set; }
[Key]
[StringLength(15)]
[DisplayName("Request Number")]
public string RequestNumber { get; set; }
[NotMapped]
public virtual WorkOrder WorkOrder { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<AuditLog> AuditLogs { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<AuthorizedUser> AuthorizedUsers { get; set; }
...
And
[Table("WorkOrder")]
public partial class WorkOrder
{
public WorkOrder()
{
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long? ID { get; set; }
[Key]
[StringLength(25)]
[DisplayName("Work Order Number")]
public string WONumber { get; set; }
[Key]
[Required]
[StringLength(15)]
[DisplayName("Request Number")]
public string RequestNumber { get; set; }
In the context I have this:
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<JobRequest>()
.HasOptional(j => j.WorkOrder);
}
...
I can easily update my JobRequest table. When I create a Work Order from the job request, I get the error Invalid column name 'WorkOrders_RequestNumber'.
What the heck have I done wrong? Do I need to add a CSDL file?
If I do, can someone break it down GUMBY style? I had a sleep study last night and I'm running on bad coffee and adrenaline.
Edited to add Navigation properties and Fluent definition.
Edit 2 - I made the changes suggested by Ivan Stoev (https://chat.stackoverflow.com/rooms/138056/discussion-between-russel-madere-and-ivan-stoev). Now everything saves, but the RequestNumber does not save in the WorkOrder table. This breaks the relationship after the data is saved. Can I get a suggestion on persisting the RequestNumber?
Edit 3 - Looking at the SQL Server Profiler, I see the following insert statement.
exec sp_executesql N'INSERT [dbo].[WorkOrder]([WONumber], [Owner], [JobName], [SubContractNum],
[ContractAmount], [Fee], [Company], [Department],
[DisplayCompany], [StartDate], [CompletionDate],
[County], [Taxable], [PPBond], [Address], [City],
[State], [Zip], [Country], [RequestedBy],
[PurchAddress], [PurchCity], [PurchState], [PurchZip],
[PurchCounty], [PurchCountry], [DescriptionOfWork],
[EntryUser], [EntryDate], [LastChangedBy], [LastChanged],
[ContractType], [Revision], [PrintURL], [RequestNumber])
VALUES (@0, NULL, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16,
@17, @18, @19, @20, @21, @22, @23, @24, @25, @26, @27, @28, @29, @30, @31, @32, @33,
@34, NULL)
SELECT [ID]
FROM [dbo].[WorkOrder]
WHERE @@ROWCOUNT > 0 AND [WONumber] = @0'...
I left the schema and data specific information off of the statement.
I see here that the ForeignKey is being inserted as a NULL. How do I set the value of the foreign key?
Upvotes: 3
Views: 2097
Reputation: 10864
If you are having an issue where a NavigationProperty
in EF is causing issues and is being reported as TableNavigationProperty
instead of Table.NavigationPreperty
is probably because there is a leftover navigation property somewhere in your models
https://github.com/dotnet/efcore/issues/15021
Upvotes: 0
Reputation: 205719
The following design represents the provided sample database schema:
Model:
[Table("JobRequest")]
public partial class JobRequest
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long? ID { get; set; }
[Key]
[StringLength(15)]
[DisplayName("Request Number")]
public string RequestNumber { get; set; }
public virtual WorkOrder WorkOrder { get; set; }
}
[Table("WorkOrder")]
public partial class WorkOrder
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long? ID { get; set; }
[Key]
[StringLength(25)]
[DisplayName("Work Order Number")]
public string WONumber { get; set; }
public virtual JobRequest JobRequest { get; set; }
}
Configuration:
modelBuilder.Entity<JobRequest>()
.HasOptional(e => e.WorkOrder)
.WithOptionalPrincipal(e => e.JobRequest)
.Map(m => m.MapKey("RequestNumber"));
Some operations:
var jobRequest = new JobRequest { RequestNumber = "RN1" };
db.JobRequests.Add(jobRequest);
db.SaveChanges();
var workOrder = new WorkOrder { WONumber = "WON1" };
db.WorkOrders.Add(workOrder);
db.SaveChanges();
var workOrder = new WorkOrder { WONumber = "WON2" };
var jobRequest = new JobRequest { RequestNumber = "RN2" };
workOrder.JobRequest = jobRequest;
db.WorkOrders.Add(workOrder);
db.SaveChanges();
or alternatively
var workOrder = new WorkOrder { WONumber = "WON3" };
var jobRequest = new JobRequest { RequestNumber = "RN3" };
jobRequest.WorkOrder = workOrder;
db.JobRequests.Add(jobRequest);
db.SaveChanges();
var workOrder = db.WorkOrders.Include(e => e.JobRequest).First(e => e.WONumber == "WON1");
var jobRequest = db.JobRequests.Include(e => e.WorkOrder).First(e => e.RequestNumber == "RN1");
workOrder.JobRequest = jobRequest;
db.SaveChanges();
or alternatively
var workOrder = db.WorkOrders.Include(e => e.JobRequest).First(e => e.WONumber == "WON1");
var jobRequest = db.JobRequests.Include(e => e.WorkOrder).First(e => e.RequestNumber == "RN1");
jobRequest.WorkOrder = workOrder;
db.SaveChanges();
var jobRequest = db.JobRequests.Include(e => e.WorkOrder).First(e => e.RequestNumber == "RN2");
jobRequest.WorkOrder = null;
db.SaveChanges();
or alternatively
var workOrder = db.WorkOrders.Include(e => e.JobRequest).First(e => e.WONumber == "WON3");
workOrder.JobRequest = null;
db.SaveChanges();
All these operations work as expected and manage/persist the hidden (shadow) WorkOrder.RequestNumber
property indirectly through navigation properties.
Note that operations on disconnected entities require special handling. If you have issues with correctly implementing disconnected entity modifications, you can create another post and provide the concrete details.
Upvotes: 1