Using an Interface with a navigation property - c#

I am trying to setup a project using Entity Framework 4, POCO, and Code-Only.
Is it possible in entity framework for type of a navigation property to be an interface?
I have a "Task" class. A Task can be assigned to a user or a group each of which are represented by a separate class and stored in separate tables. The classes look something like this:
public class User : IAssignable
{
public string Name { get; set; }
public int ID { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class Group : IAssignable
{
public string Name { get; set; }
public int ID { get; set; }
public string Manager { get; set; }
public string Department { get; set; }
}
public class Task
{
public string Title { get; set; }
public DateTime DueDate { get; set; }
public string Details { get; set; }
public IAssignable AssignedTo { get; set; }
}
Is there a way to may the AssignedTo property as a navigation property in entity framework? I assume there will have to be some type of discriminator for EF to know if it needs to look in the Users table or the Groups table but I can figure out the mapping using Code-Only or EDMX.

you can use interface in navigation property, take a look at this solution as it's the same as question:
How to use interface properties with CodeFirst

I know this is an old question, but no, there is no feature of Entity Framework (even the latest version 6) that allows you to map a navigation property with an interface type.
You could, however, map multiple navigation properties with concrete types (and a constraint that only one may be set) and provide an unmapped property of your interface type which coalesces the concrete navigation properties into a single property. Unfortunately, this may make your queries more complex because certain queries will need to know which concrete navigation properties to reference (and you can't query against your unmapped interface property).
There is significant complexity around support for polymorphic navigation properties. Consider what would have to happen in order to query your original AssignedTo property if you assume it's mapped to a column such as AssignedToId int. You'd have to union or join both User and Group entity sets and hope that a given AssignedToId appears in just one of them. This is the approach used by the Table-Per-Concrete (TPC) type mapping, but it only works with class inheritance (not interfaces) and careful planning for generating distinct ids across the participating types.

You could save yourself a lot of work by using the Text Template Transformation Toolkit (T4) supported by EF4. I found this one after a good 12 hours of looking for a way around manually creating my POCOs and interfaces,
http://blogofrab.blogspot.com/2010/08/maintenance-free-mocking-for-unit.html
Besides providing a brilliant base for unit testing, it auto-generates navigational properties based on the relationships defined in your model.

Related

Dynamic Entity Navigation Property

I have an entity called Asset, similar to below:
public class Asset
{
public int Id { get; set; }
public int TypeId { get; set; }
public int AddedById { get; set; }
public DateTime DateTimeAdded { get; set; }
public virtual AssetType Type { get; set; }
public virtual ITUser AddedBy { get; set; }
}
I want to be able to have a navigation property that is linked to a single table, but that table is dependent on what type of Asset it is. For instance, if the Asset is of the type "Printer" then I want the navigation property to link to the PrinterDetail entity. My initial way of going about this was to have unused columns in the Asset entity, but I figured that was wasteful or bad practice. Is there something that I am overlooking or is this just something that cannot be done?
Thanks for any advice given.
if you want navigate printerDetail by type you can use entityfraemwork inheritance strategy:
Table per Hierarchy (TPH)
Table per Type (TPT)
Table per Concrete class (TPC)
you have to create Model per each type and use TPT strategy for that.
and then you can use fluent api for config mapping for that.
parent Model (Asset) must define as abstract class and AssesTypes Must be Drive from the Parent.
more information

Derived Types in Entity Framework

I have a Person Class and Inventory can be two types: Sales and CustomerService.
Sales and CustomerService have their unique properties and Peron holds the common properties.
I want to be able to query
So, when creating all three classes how do i create EF relation between them? OR is there a better way to think about the division of classes?
I don't want to have Person as Abstract class because most of the time i would want to query for the common properties.
There are 3 possible approaches you can take here:
1. Store all types in a single table (Table per Heirarchy)
You would have a single Person class that contains all possible properties that would be needed between the three classes. In addition, you would add a PersonType enum to specify different types for each entry.
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
// ...
public PersonType Type { get; set; }
}
public enum PersonType
{
Sales,
CustomerService
}
This is generally the simplest and best performing approach. The biggest issue is with specialized fields. Since every type is in this one table, this table will need to contain all of the fields that any type may need. This also means all specialized fields need to be nullable, which makes it difficult to enforce specific types having specific fields.
2. Store each type in a separate table (Table per Concrete Class)
Instead of having a Person table at all, you could instead just have Sales and CustomerService tables that simply repeat the properties that would have been contained in the Person table.
public class Sales
{
public int SalesId { get; set; }
public string Name { get; set; }
// ...
}
public class CustomerService
{
public int CustomerServiceId { get; set; }
public string Name { get set; }
// ...
}
Of course, you can still take advantage of the Person abstraction in code if you want. Using code-first, you can make use of inheritance:
public class Person
{
public string Name { get; set; }
}
public class Sales : Person
{
public int SalesId { get; set; }
// ...
}
public class CustomerService : Person
{
public int CustomerServiceId { get; set; }
// ...
}
Just make sure that you only define entities for Sales and CustomerService in your DbContext subclass:
public class MyContext : DbContext
{
// Do not include a DbSet for Person.
public DbSet<Sales> Sales { get; set; }
public DbSet<CustomerService> CustomerService { get; set; }
// ...
}
The advantage of this approach is that your types are separated into clear, distinct sets. The downside is that there is no easy way to do a universal search through every single "person" since that abstraction doesn't exist as far as the database is concerned. For example, if you wanted to find someone with a specific name, you'll have to do separate searches through the Sales table and the CustomerService table manually, which may not be ideal. Also, if you end up with a person who serves a role in both sales and customer service, you'll be creating redundancy since you need to enter their information for both entries.
3. Store each type and the base type in their own tables (Table per Type)
On top of your Person class, you'll also create Sales and CustomerService classes that each specify their specialized properties and contain a reference to the Person class. This is a common principle known as composition over inheritance; since we can't effectively model inheritance in a database, we can use composition instead.
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
// ...
}
public class Sales
{
public int SalesId { get; set; }
public int PersonId { get; set; }
public virtual Person { get; set; }
// ...
}
public class CustomerService
{
public int CustomerServiceId { get; set; }
public int PersonId { get; set; }
public virtual Person { get; set; }
// ...
}
This will allow you to add the specialized properties for each type while still maintaining a universal Person table that you can search through. This will also allow you to reuse a person's information if they serve multiple roles. The downside is that creating a new Sales and CustomerService record is a little more tedious, since you'll also need to also either find an existing Person record or create a new one. This also may not be the best on performance since queries may end up requiring joins.
The approach you should take depends on your needs. If you want to go more in depth with these 3 strategies, check out this tutorial for implementing inheritance in Entity code-first:
http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx
With Entity Framework Core you can use inheritance in your database:
public class PeopleContext : DbContext {
public DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<CustomerService>().HasBaseType<Person>();
modelBuilder.Entity<Sales>().HasBaseType<Person>();
}
}
This will create one table with the properties of all derived types. Also, it will create a Discriminator-Column so that if you query your database EF Core instantiates the correct derived types:
context.Users.Add(new Sales() {
Id = 1
});
context.SaveChanges();
// This will actually be of type "Sales"
var salesPerson = context.Persons.Single(u => u.Id == 1);
For more information look here and here.
I prefer to use System.ComponentModel.DataAnnotations to apply attributes to my models such as the database table name to the class, the key(s), the foreign keys, and the inverse properties for navigation. EF will use this to auto-magically create the database table(s) with the inheritance. EF can create one table with all the properties from the derived types, or separate tables for each type including the base class (which can be abstract or not). You can search against the base type and it will return the proper implementation of the derived types. So you can get back a list containing both Sales and CustomerService objects.

Entity Framework one-to-one with a class that is sometimes independent

I have a parent class ComponentDesign:
public class ComponentDesign
{
public string Name { get; set; }
public virtual JobFile DesignFile { get; set; }
public int? DesignFileId { get; set; }
public Pdf PdfFile { get; set; }
public int? PdfFileId { get; set; }
public JobFile SealedPdfFile { get; set; }
public int? SealedPdfFileId { get; set; }
public int Id { get; set; }
public int JobId { get; set; }
}
And a child class JobFile (of which Pdf is a subclass):
public class JobFile
{
public int ID { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public ComponentDesign ComponentDesign { get; set; }
public int? ComponentDesignId { get; set; }
public int? JobId { get; set; }
}
These classes are stored in a relational database using Entity Framework. I would like to have navigation properties on both sides of the relationship, so that I can say componentDesign.PdfFile or jobFile.ComponentDesign at will.
Each property of type JobFile in ComponentDesign is optional, and a JobFile will only ever belong to oneComponentDesign. However, aJobFilemay be free-standing, not belonging to anyComponentDesign(sojobFile.ComponentDesign` would be null).
I'm struggling with how to use the Fluent API to configure this relationship. It is one-to-one. Is it possible to have the navigation properties on both sides of the relationship? Remember that a JobFile can be free-standing (so jobFile.ComponentDesign will not always be relevant), so there are JobFiles that belong to ComponentDesigns and ones that don't. The closest I feel I've come is this:
modelBuilder.Entity<ComponentDesign>()
.HasOptional(componentDesign => componentDesign.DesignFile)
.WithRequired(jobFile => jobFile.ComponentDesign);
But this seems to me to indicate that jobFile.ComponentDesign is always required, which isn't the case. I'm hesitant to just try it because it will generate some substantial migrations, so I wanted to get input first. What should my Fluent API configuration look like for this situation?
Just so that I understand the relationships:
ComponentDesign -> JobFile = Optional.
JobFile -> ComponentDesign = Optional.
This is a Zero-or-one to zero-or-one ([0/1]-[0/1]) relationship.
This can be implemented in the following way, using the the .WithOptionalPrincipal method in fluent API. With a 1-0 relationship, it's obvious which end is the principal end; same with a 1-∞ relationship. ∞-∞ relationships don't have a principal end, due to the hidden tables created that control the relationships between each. With a 0/1-0/1, or a 1-1 relationship, it's not obvious, and so you must tell the database which end to use as the principal end of the relationship. Among many other things, the pricipal is responsible for initiating, and maintaining the relationship between the tables.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure ComponentDesign & JobFile entity
modelBuilder.Entity<ComponentDesign>()
// Mark JobFile property optional in ComponentDesign entity.
.HasOptional(cd => cd.DesignFile)
// Mark ComponentDesign property optional in JobFile entity.
.WithOptionalPrincipal(jf => jf.ComponentDesign);
}
Or, you can create an EntityTypeConfiguration<> class for each entity to separate out the relationships, if there are a lot to sort through. While this does decentralise the relationships, it is more scalable, as these configuration classes can be injected via MEF once the context is configured to do so. Just an idea for future development.
If you were configuring the relationship from the JobFile end, you would use .WithOptionalDependent, in order to set the navigation correctly, instead of .WithOptionalPrincipal. It all depends on which side you configure the relationship from. The ComponentDesign entity relies on the JobFile entity a lot more than the JobFile entity relies on the ComponentDesignentity; thus it should be configured as the principal.
As stated in one of the comments above, complex properties should be adorned with the virtual keyword. This lazy loads the property, and also, when the class is intansiated, it will set the initial value to be null.
Clone the database to a test server, to work on this one problem, then implement the changes on the production model; that way there is no chance of data loss when migrating the database.

Entity Framework multiple mapping to same table DB first

I have an issue with an Entity Framework from DB model.
My issue is down to the fact that one of my models has a multiple references to one table.
public partial class Customer
{
public int Id { get; set; }
public Nullable<int> PrimaryEngId { get; set; }
public Nullable<int> AssignedDevloperId { get; set; }
public virtual Engineer Engineer { get; set; }
public virtual Engineer Engineer1 { get; set; }
}
In my model the columns are mapped respectively, however when a colleague builds the model from the same database the two are reversed.
I believe the issue is that the first mapping to in was the primaryEngId
and the Db constraint is called FK_Customer_Engineer.
And the assigned developer id was added subsequently and the DB constraint is called FK_Customer_Devloper
So alphabetically Developer come before Engineer and Entity Framework now maps them the other way round.
My code references the Engineer in quite a lot of places which now won't work
Is there any way out of this?
Many thanks
Ian
You have to add missing ForeignKey attributes on foreign keys for those two navigation properties:
[ForeignKey("Primary")]
public int? PrimaryEngId { get; set; }
[ForeignKey("Assigned")]
public int? AssignedDevloperId { get; set; }
public virtual Engineer Primary { get; set; }
public virtual Engineer Assigned { get; set; }
NOTE: Also don't use generic names for navigation properties with EF. In the nutshell one of the best things EF gives you is that you can say:
#myCustomer.Assigned.Name
etc in the view, and you are totally screwing it up with names like Engineer and Engineer1.
NOTE2: Keep Nullable<int> to code generation. int? is a lot more readable.
NOTE3: Use VS refactoring to rename properties Engineer and Engineer1 to what they should be ( PrimaryEngineer and AssignedEningeer etc). After that add ForeignKey attributes to your model. That should be enough. However, any future changes that you are doing has to be done in the Code and not in db.
IF on the other hand you are constantly regenerating entities and context code from database, make sure that all your foreign keys has meaningful names, as EF will use them to generate name.(ie it is not named Engineer1 out of blue) Rename those foreign keys to reflect what logical relationship is. Ie you most likely have the following foreign keys in db:
FK_Customer_Engineer
FK_Customer_Engineer1
You need to rename them to
FK_Customer_PrimaryEngineer
FK_Customer_AssignedEngineer
Update: you can have different column name and property name like so:
[Column("PrimaryEngId")]
[ForeignKey("Primary")]
public int? PrimaryID { get; set; }

EF Code First Navigation Property to same table

I'm new to EF and struggling to implement the following scenario. I have an entity I'd like to have a navigation property to another of the same entity. E.g.
public class Stage {
public int ID { get; set; }
public int? NextStageID { get; set; }
public string Name { get; set; }
public virtual Stage NextStage { get; set;}
}
The only example I've found so far was where the entity had a parent / child relationship, i.e. the navigation property was an ICollection of the same entity. I tried adapting this but couldn't get it to work in my instance. Also, I only need it to be one way, i.e. the entity doesn't have a 'PreviousStage' property, just a 'NextStage' one. I'm configuring using Fluent API. Could someone advise if / how this can be achieved?
I am getting this error:
Unable to determine the principal end of an association between the types 'namespace.Stage' and 'namespace.Stage'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations
Edit
Just realised in my slightly simplified example, I didn't show that NextStageID is optional (int?).
You can explicitly define the relation as follows:
public class Stage {
public int ID { get; set; }
public int NextStageID { get; set; }
public string Name { get; set; }
[ForeignKey("NextStageID ")]
public virtual Stage NextStage { get; set;}
}
you need to add a parentId and Parent navigation property
and Children navigation property so entity framework understands that is a recursive relation
check the answer in this stack Overflow link

Categories