Entity framework 6, fluent mapping of 1 to 0..1 relationship on non-primary-key columns - entity-framework-6

I'm trying to migrate an objectcontext/edmx system to dbcontext (EF6) with fluent mapping. I have a few instances like the following. Principal table has a relationship to a dependent table where a non-PK column in the dependent table holds the value of a PK column in the principal. On its own this would be a one to many relationship, but there is a unique index on the dependent table FK columns. Using EDMX mapping, this works fine as long as you define the relationship using mapping rather then referential constraints. Below is an executable example - you don't need the database because it doesn't get that far, currently:
Imports System.Data.Entity
Imports System.Data.Entity.ModelConfiguration
Module Module1
Sub Main()
Using session As New SaturnEntities
Dim res = session.BookingLegSet.Select(Function(x) New With {x.Prefix, x.ID, x.AddressDetails.Address}).ToList
End Using
End Sub
End Module
Partial Public Class BookingLeg
Public Property Prefix As String
Public Property ID As Integer
Public Property LegIndex As Integer
Public Overridable Property AddressDetails As BookingLegAddress
End Class
Partial Public Class BookingLegAddress
Public Property Prefix As String
Public Property ID As Integer
Public Property Address As String
Public Overridable Property BookingLeg As BookingLeg
Property JobLegPrefix As String
Property JobLegID As Integer?
End Class
Public Class BookingLegConfig
Inherits EntityTypeConfiguration(Of BookingLeg)
Public Sub New()
ToTable("JobLegs", "dbo")
HasKey(Function(x) New With {x.Prefix, x.ID})
HasOptional(Function(x) x.AddressDetails).WithRequired(Function(x) x.BookingLeg).Map(Function(x) x.MapKey("Prefix", "ID"))
End Sub
End Class
Public Class BookingLegAddressConfig
Inherits EntityTypeConfiguration(Of BookingLegAddress)
Public Sub New()
ToTable("JobAddresses", "dbo")
HasKey(Function(x) New With {x.Prefix, x.ID})
HasRequired(Function(x) x.BookingLeg).WithOptional(Function(x) x.AddressDetails).Map(Function(x) x.MapKey("JobLegPrefix", "JobLegID"))
End Sub
End Class
Partial Public Class SaturnEntities
Inherits DbContext
Public Sub New()
MyBase.New("data source=dbSaturn;initial catalog=Saturn;integrated security=True;MultipleActiveResultSets=True;")
End Sub
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
modelBuilder.Configurations.Add(New BookingLegConfig)
modelBuilder.Configurations.Add(New BookingLegAddressConfig)
End Sub
Public Overridable Property BookingLegAddressSet() As DbSet(Of BookingLegAddress)
Public Overridable Property BookingLegSet() As DbSet(Of BookingLeg)
End Class
BookingLeg is the principal entity and BookingLegAddress is the dependant. JobLegPrefix and JobLegID in the dependent will be either null or will hold the Prefix and ID values from a BookingLeg record. When you run this you get an error that AddressDetails has been configured with conflicting mapping information. I've tried numerous different ways to map this, but haven't got anywhere - can anyone tell me what I need to do?

Remove the
HasOptional(Function(x) x.AddressDetails).WithRequired(Function(x) x.BookingLeg).Map(Function(x) x.MapKey("Prefix", "ID"))
line from BookingLegConfig class. Every single relationships must be configured only once in a single place (part of the configuration of any of the two involved entities, but not in both). In this particular case you should keep the second configuration inside BookingLegAddressConfig class
HasRequired(Function(x) x.BookingLeg).WithOptional(Function(x) x.AddressDetails).Map(Function(x) x.MapKey("JobLegPrefix", "JobLegID"))
because it specifies the correct FK column names.
Also EF6 does not support explicit FK columns for this type of relationship - no HasForeignKey fluent API, and MapKey is for specifying shadow property (and column) names. So additionally remove the JobLegPrefix and JobLegID properties from the BookingLegAddress class:
Partial Public Class BookingLegAddress
Public Property Prefix As String
Public Property ID As Integer
Public Property Address As String
Public Overridable Property BookingLeg As BookingLeg
End Class

Related

Are there problems with using inheritance from the domain layer for models in the storage layer?

Using EF 6 code first, relatively new to separation of concerns, DI, inheritance, etc. The classes below are simplified to focus on my question. I have an MVC Project for the presentation layer, a Class Library Project for the domain layer and a Class Library Project for SQL layer.
I designed the following model in the domain layer:
Public Class TaskList
<Key> Public Overridable Property TaskListID As Integer
Public Property TaskListOwner As String
Public Property Tasks As New List(Of TaskItem)
End Class
Public Class TaskItem
<Key> Public Overridable Property TaskId As Integer
Public Property TaskName As String
Public Property TaskDesc As String
Public Property TaskOwner As String
End Class
And this model in the SQL layer using inheritance from the domain:
Public Class SqlTaskList
Inherits TaskList
<Key> Public Overrides Property TaskListID As Integer
Function SqlToDomainTaskList() As TaskList
...
Return theDomainTaskList
End Function
End Class
Public Class SqlTaskItem
Inherits TaskItem
<Key> Public Overrides Property TaskId As Integer
Function SqlToDomainTaskItem(theSqlTaskItem) As TaskItem
...
Return theDomainTaskItem
End Function
End Class
Will I run into problems later on coding like this? It just seemed like using inheritance kept me from repeating myself when designing the SQL models (the real models are of course much larger), and also allows changes in the domain model to automatically propagate into the storage model. Did I get this right, wrong, partially right? Will I have problems later on doing it like this?
Regarding separation of concerns, wouldn't be OK for the SQL layer to be more tightly coupled with the domain since the SQL layer is always saving the domain objects?

MVC Entity Framework invalid column name

I have been working with MVC 4 and Entity Framework to create a web app recently. Things have been going well with my database "ppProject" model, as shown here:
Public Class ppProject
<Key()>
Public Property ProjectID As Integer
Public Property ClientID As Integer
Public Property ProjectTitle As String
Public Overridable Property Client As ppClient
Public Overridable Property Milestones As ICollection(Of ppMilestone)
Public Overridable Property Tasks As ICollection(Of ppTask)
End Class
The problem is that I am adding a new table of employees, "ppEmployees". This way the Project can have a ProjectManager, which is a foreign key into the Employees table. These are the new models where ProjectManagerID (foreign key) is linked to EmployeeID (primary key):
Public Class ppProject
<Key()>
Public Property ProjectID As Integer
Public Property ClientID As Integer
Public Property ProjectTitle As String
Public Property ProjectManagerID As Integer 'NEW'
Public Overridable Property Client As ppClient
Public Overridable Property Milestones As ICollection(Of ppMilestone)
Public Overridable Property Tasks As ICollection(Of ppTask)
Public Overridable Property ProjectManager As ppEmployee 'NEW'
End Class
Public Class ppEmployee
<Key()>
Public Property EmployeeID As Integer
Public Property DepartmentID As Integer
Public Property FirstName As String
Public Property LastName As String
Public Overridable Property ProjectsInManagement As ICollection(Of ppProject)
Public Overridable Property TimeItems As ICollection(Of ppTimeItem)
Public Overridable Property Department As ppDepartment
End Class
When I change my project model and add the employee model, I am getting the error
Invalid column name 'ProjectManager_EmployeeID'
The line of code that is triggering this is when I first access my projects in a view with:
#For Each proj In client.Projects
Any ideas at what is causing this? This must be a naming convention problem or something simple because I haven't had any errors with any of my other table models prior to this.
EDIT - See my answer below. Very confused about what Entity Framework is doing here.
In Entity Framework the name of the field must match the name of the column.
otherwise EF wouldnt know how to map the fields unless you decorate the property with the column attribute like you did in your answer.
Ok I think I've fixed this. I had to make the following changes to the "ppProject" class:
<Column("ProjectManagerID")>
Public Property EmployeeID As Nullable(Of Integer) 'Has to be set, dont know why
If anyone knows why my property has to be named EmployeeID, please let me know. I'm very curious.
I had a similar problem about a month ago. I dropped the table and created a new one and the problem was solved. that is after i have tried other ways that did not work

Nested Object Scaffold ASP.net MVC 3 VB.net

I am complete beginner with ASP.net and VB.net, I created two classes one for Teams and another for Fixtures which will take in 2 teams.
Imports System.Data.Entity
Public Class Team
Public Property ID() As Integer
Public Property Name() As String
Public Property Points() As Integer
End Class
Public Class TeamDBContext
Inherits DbContext
Public Property Teams() As DbSet(Of Team)
End Class
Imports System.Data.Entity
Public Class Fixture
Public Property ID() As Integer
Public Property Week() As Integer
Public Property HomeTeam() As Team
Public Property AwayTeam() As Team
End Class
Public Class FixtureDBContext
Inherits DbContext
Public Property Fixtures() As DbSet(Of Fixture)
End Class
I created a FixturesController with the read/write actions and views. However when I go to create a Fixture in my application I only see a field for Week and not field for HomeTeam or AwayTeam.
Well you need to add them manually. Brad Wilson wrote a nice article explaining in details how you could make the templated helpers to recursively descend in your nested models.
Also as a side remark you probably don't need 2 db contexts, one should be enough and it could contain both your Teams and Fixtures:
Public Class FixtureDBContext
Inherits DbContext
Public Property Teams() As DbSet(Of Team)
Public Property Fixtures() As DbSet(Of Fixture)
End Class

Cannot add ASP.NET MVC Controller

I'm new to ASP.NET MVC, altough could call myself experinced programmer in web forms field.
I'm learning MVC now. Trying to add controller with Entity framework abolities.
Here is below code of model class:
Imports System.Data.Entity
Public Class Users
Public Property ID() As Integer
Public Property Login() As String
Public Property Password() As String
Public Property Avatar() As Image
Public Property Country() As Integer
Public Property City() As Integer
Public Property Phone() As String
Public Property Email() As String
Public Property Registered() As Date
End Class
Public Class StopSaleDBContext
Inherits DbContext
Public Property Users() As DbSet(Of Users)
End Class
When I'm adding controller I got error Unable retrieve metadata from ProjectName.Users Object reference not set to an instance of object.
Compile your project and try again.

Entity Framework With Database

Here are the entities that i have...
Public Class Account
Public Property AccountId As integer
Public Property AccountDescription As String
Public Property Transactions As List(Of Transaction)
End Class
Public Class Transaction
Public Property TransactionId As Integer
Public Property AccountId As Integer
Public Property TransactionDescription As String
End Class
i would like to make it suc that when i do "db.Account.find(1)" for example it also loads in the list of all transactions which have the coresponding AccountId. I'm not too sure what type of relationship this is?? anyway, right now i can do
Dim acct As Account = db.Account.Find(1)
acct.Transactions = from ts in db.transactions select ts where ts.AccountId = acct.accountid
but i know this is not the correct way, there must be a way to map this out so that entity can just load everything in one shot right? Thanks for any help.
You can use db.Account.Include("Transactions").SingleOrDefault(1) or put Transactions as virtual (I think it is Overridable in vb).

Resources