Entity Framework query with simple join - c#

I am using Entity Framework 6 in a project and am having trouble creating a query.
Say my classes are defined like:
public class MyContext : DbContext
{
public MyContext(string connectionString) : base(connectionString)
{
}
public DbSet<EntityXXX> XXXSet { get; set; }
public DbSet<EntityYYY> YYYSet { get; set; }
}
public class EntityXXX
{
public string XXXName { get; set; }
public int id { get; set; }
public int YYYid { get; set; }
}
public class EntityYYY
{
public string YYYName { get; set; }
public int id { get; set; }
}
The YYYid property of EntityXXX is the 'id' of the EntityYYY instance that it relates to.
I want to be able to fill a Grid with rows where the first Column is XXXName and the second column is YYYName (from its related EntityYYY), but I can't see how to do this?
I'm sure it's really simple, but I'm new to EF.

You need to put a virtual navigation property on your EntityXXX
public virtual EntityYYY YYY { get; set; }
Then you can do a projection:
db.XXXSet
.Select(x => new { x.XXXName, YYYName = x.YYY.YYYName })
.ToList();
Which will get you the list you need.

Related

Filtering on the Collection Navigation property

I would like to filter my 'TranslationSet' entities, based on their 'Translations' Collection Navigation Property.
E.g.
If a 'Translation' has a 'LanguageId' of 5 (Italian), then the 'TranslationSet' that contains this 'Translation' should be removed from the result.
Here are my Entity classes:
public class Language
{
public int LanguageId { get; set; }
public string NationalLanguage { get; set; }
//Make table multi tenanted.
public int TenantId { get; set; }
public ApplicationTenant Tenant { get; set; }
public List<Translation> Translation { get; set; } = new List<Translation>();
}
public class Translation
{
public int TranslationId { get; set; }
public string TranslatedText { get; set; }
public int LanguageId { get; set; }
public Language Language { get; set; }
//Make table multi tenanted.
public int TenantId { get; set; }
public ApplicationTenant Tenant { get; set; }
public int TranslationSetId { get; set; }
public TranslationSet TranslationSet {get; set;}
}
public class TranslationSet
{
public int TranslationSetId { get; set; }
public int TenantId { get; set; }
public ApplicationTenant Tenant { get; set; }
public IEnumerable<Translation> Translations { get; set; }
}
Here is my attempt
From the image you can see that the query fails because a Translation exists with LanguageId of 5.
I have tried many many attempts to resolve this but I can't even get close the LINQ which returns my query correctly.
Please let me know if any further clarification is needed and thanks in advance to anybody who offers help.
My rule of the thumb that nearly always work is: start by querying the entities you want. That will prevent duplicates as you see in your query result. Then add predicates to filter the entities, using navigation properties. That will be:
var sets = TranslationSets // start the query here
.Where(ts => ts.Translations.All(t => t.LanguageId != 5)); // Filter
Or if you like this better:
var sets = TranslationSets // start the query here
.Where(ts => !ts.Translations.Any(t => t.LanguageId == 5)); // Filter
EF will translate both queries as WHERE NOT EXISTS.

Query Parent Class EF inheritence linq query

Hello everyone so here is my basic EF class structure:
public abstract class StandardEngineeredModel
{
[Key]
public string ModelNumber { get; set; }
public int VoltageInput { get; set; }
}
public class DualRatedInputEngineeredModel : StandardEngineeredModel
{
public int SinglePhaseVoltageInput { get; set; }
public string SinglePhaseHzInput { get; set; }
public decimal SinglePhaseAmpsInput { get; set; }
public bool SeparateInput { get; set; }
}
And my context:
public class LabelPrintingContext : DbContext
{
public virtual DbSet<StandardEngineeredModel> StandardEngineeredModels { get; set; }
}
What I am trying to do is query for a StandardEngineeredModel. Here is an example of a query I tried:
public StandardEngineeredModel GetEngineeredOrder(string modelNumber)
{
using (context = new LabelPrintingContext())
{
return (from s in context.StandardEngineeredModels
where s.ModelNumber == modelNumber
select s).FirstOrDefault();
}
}
But when executing this it says invalid column name SeparateInput which seems to be happening because of the extra column being added to my StandardEngineeredModels table due to the DualRatedInputEngineeredModel inheriting from it. Not sure how to go about this, I don't want to return an Iqueryable, but no matter what I try it tells me the SeparateInput is an invalid column name.
I also tried casting it first and get the same error:
public StandardEngineeredModel GetEngineeredOrder(string modelNumber)
{
using (context = new LabelPrintingContext())
{
return (from s in context.StandardEngineeredModels.OfType<StandardEngineeredModel>()
where s.ModelNumber == modelNumber
select s).FirstOrDefault();
}
}
Do I need to make a DTO or something? Am I just doing this completely wrong?
Thanks in advance for any opinions / help!

Converting infinitely nested objects in .NET Core

EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?

Mapping composite poco to EF objectcontext entities

I have to produce an output from 3 separate tables(with a couple of fields from each table) into 1 output. I have a class that represents that output. The data is pulled from linq query of EF 6.1.x ObjectContext(Im stuck with using ObjectContext due to the nature of my clients needs....) entities (the 3 classes properly joined in the query) to a list of the new class (List<>). I populate a grid and all is fine. However the user wants to edit the data in the grid and now I need to push those new changes back.
My question is this: Can I map my new class back to the entities field to field? Or am I stuck with iterating through the collection and updating the tables individually? I thought I could map but I haven't run across anything that substantiates this.
Could you not do this using the "Proxy" pattern?
I've done a 2 entity + Wrapper example pseudo example below.
EF would "Save" the SuperWrapper.DeptProxy and the SuperWrapper.EmpProxy.
public partial class DepartmentEFEntity {
public virtual Guid? DepartmentUUID { get; set; }
public virtual string DepartmentName { get; set; }
public virtual ICollection<EmployeeEFEntity> Employees { get; set; }
}
public partial class EmployeeEFEntity
{
public virtual Guid? ParentDepartmentUUID { get; set; }
public virtual Guid? EmployeeUUID { get; set; }
public virtual DepartmentEFEntity ParentDepartment { get; set; }
public virtual string SSN { get; set; }
}
public class SuperWrapper
{
internal DepartmentEFEntity DeptProxy { get; private set; }
internal EmployeeEFEntity EmpProxy { get; private set; }
public SuperWrapper(DepartmentEFEntity dept, EmployeeEFEntity emp)
{
this.DeptProxy = dept;
this.EmpProxy = emp;
}
public string DepartmentName
{
get { return null == this.DeptProxy ? string.Empty : this.DeptProxy.DepartmentName; }
set { if(null!=this.DeptProxy{this.DeptProxy.DepartmentName =value;}}
}
public string EmployeeSSN
{
get { return null == this.EmpProxy ? string.Empty : this.EmpProxy.SSN; }
set { if(null!=this.EmpProxy{this.EmpProxy.SSN =value;}}
}
}

Entity Framework navigating using navigation properties more than one level

I have Entity model classes as follows
public partial class User
{
public User()
{
this.webpages_Roles = new HashSet<webpages_Roles>();
}
public int UserID { get; set; }
public virtual ICollection<webpages_Roles> webpages_Roles { get; set; }
}
.
public partial class webpages_Roles
{
public webpages_Roles()
{
this.Users = new HashSet<User>();
this.Roles_X_ApplicationModules =
new HashSet<Roles_X_ApplicationModules>();
}
public int RoleId { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Roles_X_ApplicationModules>
Roles_X_ApplicationModules { get; set; }
}
.
public partial class Roles_X_ApplicationModules
{
public long ID { get; set; }
public Nullable<int> ModuleID { get; set; }
public Nullable<int> RoleID { get; set; }
public Nullable<bool> ViewPermission { get; set; }
public virtual ApplicationModule ApplicationModule { get; set; }
public virtual webpages_Roles webpages_Roles { get; set; }
}
.and
public partial class ApplicationModule
{
public ApplicationModule()
{
this.Roles_X_ApplicationModules =
new HashSet<Roles_X_ApplicationModules>();
}
public int ModuleID { get; set; }
public virtual ICollection<Roles_X_ApplicationModules>
Roles_X_ApplicationModules { get; set; }
}
you can see User object has a navigation property to webpages_Roles which again has navigation property to Roles_X_ApplicationModules and which in turn navigates to ApplicationModule..
now I want to get all the ApplicationModule from User..how do I write query using navigation properties..
I tried something like this..
var appModules = user.webpages_Roles.SingleOrDefault()
.Roles_X_ApplicationModules.Where(z => z.ViewPermission == true)
.Select(x => x.ApplicationModule);
but problem with this is, it doesn't issue a single query to database. It splits the query to get the webpages_Roles at SingleOrDefault then another query to get the Roles_X_ApplicationModules based on the RoleId and at the end as many queries as Roles_X_ApplicationModules matching the condition to get the ApplicationModule.
How do I write the LINQ query so that a single sql query is issued to database?
You can use Include() to do this.
Example:
card = Cards.Include(l => l.DocumentLinks)
.Include(l => l.Charges.Select(ch => ch.DocumentLinks)
.SingleOrDefault(c=>c.Id==id);
This is for three linked Entities:
public class Card
{
public Guid Id{get;set;}
public virtual ICollection<DocumentLink> DocumentLinks{get;set;}
public virtual ICollection<Charge> Charges{get;set;}
}
public class Charge
{
...
public virtual ICollection<DocumentLink> DocumentLinks{get;set;}
}
public class DocumentLink
{
...
}
try this:
var appModules = from u in user
from w in u.webpages_Roles
from am in w.Roles_X_ApplicationModules
where am.ViewPermission == true
select am;
if you want eager loading then you just need to call ToList:
var appModules = (from u in user
from w in u.webpages_Roles
from am in w.Roles_X_ApplicationModules
where am.ViewPermission == true
select am).ToList();

Categories