AutoMapper Queryable Extensions with Entity Framework - how to get OUTER joins? - entity-framework

I have a Job entity with an optional Contract child entity (using Entity Framework)
public class Job
{
public string Title { get; set; }
public Guid? ContractId { get; set; }
public virtual Contract Contract { get; set; }
}
public class Contract
{
public DateTime StartDate{ get; set; }
}
I have the following DTO
public class JobDto
{
public string Title { get; set; }
public DateTime ContractStartDate { get; set; }
}
I project to the DTO using AutoMapper Queryable extensions.
c.CreateMap<WorkTask, WorkTaskDtoLite>();
var jobDtos = _context.Jobs.ProjectTo<JobDto>().ToList();
Then this generates INNER joins, so does not return any JobDtos where there is no Contract. I need OUTER joins...
I'm really not sure how to fix this. I have referred to https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions but this does not seem to address this basic issue.
Any help appreciated!
UPDATE
Thanks all but seems to be an underlying issue with Entity Framework Core RC1.
See bug report here:
https://github.com/aspnet/EntityFramework/issues/3186
With suggested work-around here:
https://github.com/aspnet/EntityFramework/commit/c4e44471b6f41f96d37b1acfbbb4cc97cd11ee89

Related

.NET Core Entity Framework linking subtable to property

This is an existing .NET Core 3.1 project I inherited.
I have a class referring to a database table
public class SupportContract
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public int SupportContractStatusId { get; set; }
public virtual SupportContractStatus SupportContractStatus { get; set; }
}
and a sub table with a foreign key
public class SupportContractStatus
{
public int Id { get; set; }
public string SupportContractStatusName { get; set; }
}
This works fine I can get
supportContract.SupportContractStatus.SupportContractStatusName
But if I rename SupportContractStatusId to ContractStatusId in C# and the database, I get an error "SupportContractStatusId missing".
I cannot find any link between the column SupportContractStatusId and table SupportContractStatus anywhere in code nor is there any mention of the foreign key.
There is no link in the DbContext either.
Is this naming convention assumed by Entity Framework? How does the framework know of the foreign key?
Yes, the naming convention that EF expects by default is based on the class name, not the property name. It will look for ClassNameId or ClassName_Id. You can link the FK either through annotation or configuration.
I.e.
public int ContractStatusId { get; set; }
[ForeignKey("ContractStatusId")]
public virtual SupportContractStatus ContractStatus { get; set; }
Configuration is done through IEntityTypeConfiguration implementations or by implementing the OnModelCreating method in the DbContext and configuring the relationship within the modelBuilder. For occasional deviations from convention, the attribute approach can generally cover everything.

EF 5 code first optional one to one mapping accessing foreign key fields on the model

This question is basically a repeat of this question regarding EF4 CTP but specific to EF 5.
I have a POCOs set up such that
public class ClassPrinciple
{
public int ClassPrincipleID { get; set; }
public virtual ClassDependent ClassDependent{ get; set; }
}
and
public class ClassDependent
{
public int ClassDependentID { get; set; }
public virtual ClassPrinciple ClassPrinciple{ get; set; }
}
in my model builder I create the optional one to one mapping like this
modelBuilder.Entity<ClassPrinciple>().HasOptional(p => p.ClassDependent)
.WithOptionalDependent(s => s.ClassPrinciple);
this creates, on the ClassPrinciples table a column called ClassDependent_ClassDependentID . I would like to be able to reference the data in this column through a property on the ClassPrinciple model but I seem unable to do so. The web page I linked to at the top of this question states:
EF in general only supports exposing FK properties on your entities in
one:many relationships (unless the FK is also the PK). This is
somewhat artificial but a side effect of EF not supporting non-PK
unique constraints. We are working on support for unique constraints
for EF at the moment but it won't be there in our first RTM of Code
First.
Sorry not to have a better answer as there really isn't a workaround
at this stage.
Is this still the case or is there a way to resolve this. I have tried fluent api map to column and data annotations in all sorts of combinations without success.
use this code :
public class ClassPrinciple
{
public int ClassPrincipleID { get; set; }
public int ClassDependentId { get; set; }
[ForeignKey("ClassDependentId")]
[InverseProperty("ClassPrinciple")]
public virtual ClassDependent ClassDependent{ get; set; }
}
public class ClassDependent
{
public int ClassDependentID { get; set; }
[InverseProperty("ClassDependent")]
public virtual ClassPrinciple ClassPrinciple{ get; set; }
}

Breeze - self referencing entity

i get some problem using Breeze to execute queries via my ASP.NET web api application.
Here is my entity definition that i want to request on :
[Serializable]
[DataContract]
public class Subject
{
public Subject()
{
Subjects = new List<Subject>();
}
[DataMember]
public int Id { get; set; }
[DataMember]
public String Name { get; set; }
[DataMember]
public Subject Parent { get; set; }
[DataMember]
public IList<Subject> Subjects { get; set; }
}
and here is the query in my datacontext.js file
var query = EntityQuery.from("Subjects");
manager.executeQuery(query)
.then(function (data) {
// do something with data.results
})
.fail(function (error) {
});
but the query always fails with an error saying "expected object"
All other queries on other "simple" entities works fine.
If i remove the properties "Parent" and "Subjects" from my Subject Entity,
the query works.
Does anyone have an idea ?
Thanks !
Breeze needs a foreign key in order to fix up the relations between entities and you're missing it in your Subject class definition:
[DataMember]
public System.Nullable<int> ParentId { get; set; }
Or, if you are using non-conventional naming, be sure to add the ForeignKey tag to the navigation:
[DataMember]
[ForeignKey("FKParentId")]
public Subject Parent { get; set; }
You could also define it via Fluent Interface. You will find more on that at http://msdn.microsoft.com/en-us/data/hh134698.aspx.
Thanks !
i added :
[DataMember]
public System.Nullable<int> ParentId { get; set; }
and it works fine now.

Entity Framework 5 inheritance generating as TPT instead of TPH?

I'm trying to implement various tables that inherent a groups table. When I generate the database from the model it comes out as type-per-table instead of type-per-inheritance like I would like.
I have:
Group set to abstract
Each group type table is mapped to Group conditionally when type(column) = a different int for each table
Can anyone point me in the right direction for what I need to do to change this to type per inheritance?
EDIT: by request via comment here is my db set for group, and none of the group types of a dbset
public DbSet<Group> Groups { get; set; }
Here are the generated classes:
Group:
public abstract partial class Group
{
public Group()
{
this.GroupHierarchies = new HashSet<GroupHierarchy>();
this.GroupHierarchies1 = new HashSet<GroupHierarchy>();
this.NetworkActions = new HashSet<NetworkAction>();
this.PermissionAssignments = new HashSet<PermissionAssignment>();
this.UserProfiles = new HashSet<UserProfile>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Acronym { get; set; }
public string Description { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public virtual ICollection<GroupHierarchy> GroupHierarchies { get; set; }
public virtual ICollection<GroupHierarchy> GroupHierarchies1 { get; set; }
public virtual ICollection<NetworkAction> NetworkActions { get; set; }
public virtual ICollection<PermissionAssignment> PermissionAssignments { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
}
One of the group types:
public partial class HoaManagementCompany : Group
{
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
The other group type, there will be many more in the future but only these two until I get it to work.
public partial class HoaAttorney : Group
{
public string Address { get; set; }
}
When I generate the database from the model...
Are you using Model-First strategy? This unfortunately would make it difficult to get TPH inheritance for your model (which would be easy for Code-First or Database-First strategy).
(Default inheritance mapping for Code-First is TPH, so you should not have your problem with Code-First.)
Out of the box TPH is not available with Model-First. The default inheritance strategy for Model-First is TPT and there is no easy way to switch to TPH in the model designer:
It is possible to map to a TPH inheritance using Model First but you
would have to write your own database generation workflow which is
complex. You would then assign this workflow to the Database
Generation Workflow property in the EF Designer. An easier alternative
is to use Code First.
There is an additional tool from Microsoft - the Entity Designer Database Generation Power Pack - which supports TPH database generation workflow for Model-First. But the problem is that it doesn't look very well maintained (last update from May 2012) and it doesn't support Visual Studio 2012. But if you use VS 2010 you can try it.
You should only use your Groups DBSet for TPH.
Also make sure you aren't adding Table annotations to the poco classes
Try following this blog, it worked for me in the past.
Inheritance with EF Code First: Part 1 – Table per Hierarchy (TPH).
Also talks about Table per Type (TPT) and Table per Concrete class (TPC) Inheritances.

Entity Framework 5 code first not mapping a model

I have been working with EF5 trying to build an application and have run into a small problem.
I have created a model like
public class TargetBusinessModel
{
public int Id { get; set; }
public Guid BusinessId {get; set; }
public Business Business { get; set; }
public string ContactName { get; set; }
public string ContactTitle { get; set; }
public string ContactPhone { get; set; }
}
Updated the Context file
public DbSet<TargetBusinessModel> TargetBusinessModels { get; set; }
My problem is none of the properties from Business are mapped within the database.
The Business Model I am trying to add is from another project, I am not sure if that's the reason.
I don't mind if the code first creates a separate table for my Business model or combines them together.
Can anyone help out?
Try to add DbSet for Business entities to your DbContext implementation:
public DbSet<Business> Businesses { get; set; }