EF 6.1: Abstract Base Class - entity-framework-6

Upgrading Entity Framework from 6.0.2 to 6.1 caused an Exception building my DBContext.
The abstract type 'Test1Data' has no mapped descendants and so cannot
be mapped. Either remove ' Test1Data ' from the model or add one or
more types deriving from ' Test1Data ' to the model.
The situation is I have to classes (Test1 and Test2) in different projects but no reference between these projects and I want to have a relationship in my database :
Public Class Test1
Public Property Test2 As Test2 //This is not working
End Class
Public Class Test2
.....
End Class
To get the relationship in my database before EF 6.1 I made a class in my data layer (where I have the references to the different projects):
Public MustInherit Class Test1Data
Inherits Test1
Public Property Test2 As Test2
End Class
Until now this worked for me. EF made the right relation in my database. I declared the class 'MustInherit' because I did not want to have a Discriminator column in my database.
But this is not working anymore. Can anybody please help me ?

Related

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

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

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?

Need help working with Abstract Classes and Generics

i'm trying to build a class library for all of my mvc-5 projects. For that task i started with setting up some Abstract Classes for my DB Context and Indentity User like this
Public MustInherit Class ApplicationUserAbstract
Inherits IdentityUser
End Class
Public MustInherit Class DatabaseContextAbstract
Inherits DbContext
Public Property Users as DBSet(of ApplicationUserAbstract)
Sub New()
MyBase.New()
End Sub
Public Sub New(nameOrConnectionString As String)
MyBase.New(nameOrConnectionString)
End Sub
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
MyBase.OnModelCreating(modelBuilder)
End Sub
End Class
I think i have to get another approach to set DatabaseContextAbstract.Users to the correct Class inherting something like T of ApplicationUserAbstract. Any sugestions for that? I have no clue how to pass this to Users except Using something like
Public MustInherit Class DatabaseContextAbstract(of T as ApplicationUserAbstract)
Inherits DbContext
Public Property Users as DBSet(of T)
End Class
My next question: how would i access the current Instance of DatabaseContextAbstract in my abstract class? All approaches of DatabaseContextAbstract(of DatabaseContextAbstract(... would be nonsense...
EDIT:
The basic idea behind this is to pack Tables and Functions in that abstract Classes. e.g. There are the same UserRight and Group Tables behind every ApplicationUser in all of my projects. But every project may have project specific tables additionally to the base tables. There is still just one Application user in every project.
I don't see a whole lot of point to what you're doing here. IdentityUser is already abstract. It's intended that you're going to create a concrete class that inherits from it. If you perhaps intended to have multiple different types of users that all shared some subset of custom properties, I could see maybe adding an abstract subclass of IdentityUser that implements those, but you're not doing that here. However, even if you did, the user for Identity is a bit of a special case. You can only have one user table, so inheritance must start from a concrete base class, regardless. For example, the following will work fine:
public class ApplicationUser : IdentityUser {}
public class FooUser : ApplicationUser {}
public class BarUser : ApplicationUser
This will not work:
public abstract class ApplicationUserAbstract : IdentityUser {}
public class FooUser : ApplicationUserAbstract {}
public class BarUser : ApplicationUserAbstract {}
In the second scenario, FooUser and BarUser would get separate tables, which is not supported by Identity. In the first scenario, single-table inheritance will be utilized so FooUser and BarUser will be in the same table as ApplicationUser, with a discriminator column.
When it comes to your context, again, there's limited utility in having a base abstract context class. The context is inherently tied to a database, and it doesn't make sense to have multiple context each interacting with its own unique database that are all virtually carbon-copies. Even if you're dealing with a multi-tenant app, you only need one context. The individualization of the databases would be handled via the connection string, not which context class is utilized.
Finally, if you're using Identity, your context should inherit from IdentityDbContext, not DbContext. Among other things IdentityDbContext already contains a DbSet for users, so the one you added is unnecessary.
Long and short, none of this code does anything for an application. It's pointless abstraction for the sake of abstraction.

Can't create MVC4 controller for classes with a base class (Generated from Entity Framework)

I am using Entity Framework 5 with MVC4 to create a small test-app using Model First.
I have two projects, a data project, and a ui project which references data.
I have my model MYModel.edmx in data which has the following entity's
[ITEM]
[BOOK][DVD]
Where "book" and "dvd" have a base type of the abstract class "Item".
Using the code-generation, it creates the classes for these 3 tables and my dbContext as so:
public DbSet<Item> Items {get;set;}
Not creating any DbSet for accessing "Books" or "DVDs".
IF I try to create a new controller using my data context and a model class of "Books" I get the following error
mynamespace.data.books is not part of the specified mynamespace.data.dbcontext class, and the mynamespace.data.dbcontext class could not be modified to add a dbset<mynamespace.data.books> property to it. (For example )
What is the correct way to go about using EF with base types and model first as I am clearly doing something wrong, should I even be using Model first? Would it be easier to use Code first for this scenario and create the DBContext myself?
I'm not terribly familiar with model-first, but try adding this in your mynamespace.data namespace:
public class DVD : Item{
//Put your DVD specific properties here
}
public class Book : Item{
//Put your Book specific properties here
}
Don't add primary keys here, they will both inherit the ItemId primary key, because in the database both DVD and Book are being stored in the Item table.
Then, add the two models to your context:
public DbSet<DVD> DVDs {get;set;}
public DbSet<Book> Books {get;set;}
A good reference to implementing Table-Per-Hierarchy via code-first can be found here, I'm sorry i don't know of any model-first reference: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-inheritance-with-the-entity-framework-in-an-asp-net-mvc-application
I had a same problem, but I don't know what causes it. All you need to do is:
Compile the project
Right click your Controllers folder to add your controller
In Data Context class, Add Controller dialog box, manually type your context, and click Add
Hope it help

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

Resources