I found some questions that looked similar, but not exactly the same so I'll go for it.
I'm using EF to retrieve 2 tables. These tables/entities have no real "is a" relationship. They just happen to have a couple of common fields which I want to expose in a list containing the first N entries of a combination between the two tables. Each row has to have some way of identifying which type it is and which instance it points to.
I have solved the problem, but I guess I was wondering if there was a better way. My solution was to create a ViewModel class:
intenal class EntityAEntityBCombination
{
public int? EntityAID { get; set; }
public int? EntityBID { get; set; }
public string CommonProperty { get; set; }
}
Then I did this:
var results = (
from a in EntityAList select new EntityAEntityBCombination
{ EntityAID = a.Id, EntityBID = null, CommonProperty = a.CommonProperty }
).Concat(
from b in EntityBList select new EntityAEntityBCombination
{ EntityAID = null, EntitiyBID = b.Id, CommonProperty = b.CommonProperty }
).Fetch(N)
It works, but seems dirty. Any suggestions?
Have a look at this, perhaps it doesn't work straight out of the box, but it should give you an idea:
public class EntityA : IEntity
{}
public class EntityB : IEntity
{}
List<IEntity> results =
(from a in EntityAList select a).Cast<IEntity>()
.Concat(
(from b in EntityBList select b).Cast<IEntity>()
)
.Fetch(N).ToList();
foreach (IEntity entity in results)
{
if (entity is EntityA)
// do something with entity A
if (entity is EntityB)
// do something with entity B
}
Related
There are 3 entities, let's say they are presented in this way:
**1 - entity**
class A
int id ;
int Name;
[Foreign key]
int id_B;
List C;
**2 - entity**
class B
int id ;
int Name;
List A;
**3 - entity**
class C
int id;
int Name;
[Foreign Key]
int id_A;
created an entity DTO (Everything is the same only without foreign keys)
1
class ADTO
int id ;
int Name;
List C;
2
class BDTO
int id ;
int Name;
List A;
3
class CDTO
int id;
int Name;
Now the request looks like this:
var quer = (await _context.A
.Include(b => b.B)
.Include(c => c.C)
.Where(u => u.Id == 1).ToListAsync())
.Select(a => new ADto
{
Id = a.Id,
//How to get information about entity B here by converting to DTO
C = a.C.Select(cdto => new CDTO{ Id = cdto.Id, Name = cdto.Name}).ToList(),
});
How to get information about entity B here by converting to DTO?
If you are querying "A" as your top-level entity then I believe you're just missing a navigation property to it's associated "B". (As it contains the B_Id FK)
1 - entity
public class A
{
public int id { get; set; }
public string Name { get; set; }
[ForeignKey("B")]
public int id_B { get; set; }
public virtual B B { get; set; }
public virtual ICollection<C> Cs { get; set;} = new List<C>();
}
Then when you project your Entities to DTOs using Select:
var query = (await _context.A
.Where(a => a.Id == 1)
.Select(a => new ADto
{
Id = a.Id,
B = new BDTO { Id = a.B.Id /* ... */ },
Cs = a.Cs.Select(c => new CDTO{ Id = c.Id, Name = c.Name}).ToList(),
}).Single();
Note that when using .Select you do not need to use .Include to reference related entities, that is only used to eager load related entities where you want to return an entity graph. (Such as when reading the entities to update values from DTOs) Also, be wary of using any ToList operations prior to using a Select as this will load entities into memory before applying things like filters, and negates the optimization of queries to fill just what Select needs.
});
Normally, I would suggest you implement an interface, that is provided on the constructor of the resulting object
so:
public interface IDbOjbect{
int Id {get;set;}
string Name{get;set;}
}
and then on your DTO object
public Class DtoObject {
public DtoOjbect(IDbOjbect source)
{
//Mapping done here.
}
}
Because then you can implement the interface on any persistence layer object, and the mapping will still work.
Because then the linq query is simply:
DbOjbectList.Select(x => new DtoObject(x));
provided DtoOjbect implements the interface.
your C would look like this:
public partial class C {
public int id {get;set;}
public string Name {get;set;}
}
public partial class C : IDbOjbect {
}
and your CDTO would look like:
public Class CDTO{
public int Id {get;set;}
public string Name {get;set;}
public CDTO(IDbOjbect source)
{
Id = source.Id;
Name = source.name;
}
}
Want to be able to make a DTO from B?
Implement IDbOjbect on your B
by using
public partial class B {
public int id {get;set;}
public string Name {get;set;}
}
public partial class B : IDbOjbect {
}
and now any C or B can be made into a CDTO.
Best part is, you can make a generic method for your B and C, use the "Where" keyword after you generic definition, and then use the Interface as the type, now you can make a single method that does the same thing based on what has the interface implementation, and this will also work for A, if you implement the interface on A.
Without further modification.
So now that you are asking questions, you original question doesn't, lets expand.
Lets say you have a ResumeInfo Object that only B has available.
You then use the NullPointer pattern together with interface segregation principle.
So you create an interface on your resumeInfo class
Example:
public interface IResumeInfo
{
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
}
Then on your ResumeInfo Object:
public partial class ResumeInfo
{
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
}
public partial class ResumeInfo : IResumeInfo
{
}
Then lets say you want a single DTO object:
public class DTOUserAndResume
{
public int id {get;set;}
public string Name {get;set;}
string PlaceOfEmployment {get;set;}
DateTime StartOfEmployment {get;set;}
DateTime? EndOfEmployment {get;set;}
public DTOUserAndResume(IDbOjbect source, IResumeInfo resumeInfo)
{
Id = source.Id;
Name = source.name;
PlaceOfEmployment = resumeInfo.PlaceOfEmployment;
StartOfEmployment = resumeInfo.StartOfEmployment ;
EndOfEmployment = resumeInfo.EndOfEmployment ;
}
}
Now on B? I think you said you have resume data, but not on C?
you implement the IResumeInfo on both, but on B, you just get whatever data is there, but on C that has no data? NullOjbect Pattern.
Implement the interfacce, but make it return nothing.
So PlaceOfEmployment is always "" or Null.
Start data is always 1900-01-01 00:00:00 or whatever you want "nothing" to be on a not nullable object, and null on the end of employment.
So you simply claim that the data is the equavilant of a none-existing data set, because, it doesn't have a dataset to provide.
But you dont need to make a new DTO, you can just update the constructor on CDTO, it will also work fine. It might just get a bit confusing in regards to naming and stuff.
This should result in a call that looks like:
C = a.C.Select(cdto => new CDTO{cdto, cdto.ResumeInfo}).ToList();
I'm not sure what I want is something one should expect from EF, but I think I've seen this in other ORMs and this should be quite common for it to be solved in EF - so I'm asking if it has been.
I want to be able to eagerly load foreign key entities when querying EF, but only their ids, as the other part of objects will be loaded much later.
I have:
class A {
public int Id { get; set; }
public B B { get; set; }
}
class B {
public int Id { get; set; }
// .... more properties
}
And a web API, that should return a list of all As, with this view model:
class AViewModel {
public int Id { get; set; }
public int BId { get; set; }
}
I want to make sure I do not include B table join when querying - for performance reasons. I'm also using automapper to map from A to AViewModel.
Currently the best way I found to do this is:
var a = context.As;
var aList = a.Select(x => new { model = x, bid = x.B.Id }).ToList();
return Ok(mapper.Map<List<AViewModel>(aList));
Unfortunately this means that I have to add mapping from new { model = x, bid = x.B.Id } to AViewModel, that is really unconvenient.
I'd prefer to just be able to write:
var a = context.As;
var aList = a.ToList();
return Ok(mapper.Map<List<AViewModel>(aList));
But in this case it fails with NullReferenceException, because every item of aList has B property null.
I could write context.As.Include(x => x.B) but this will join B table, that I would like to avoid.
I think I have seen some ORMs being able to fill in B objects with empty objects, except for ids - and that is the behavior I'm looking for in EF. Can it do that?
If not maybe one can suggest a nicer way of solving a problem? maybe I can fix this somehow with lazy proxies?
Put the foreignKey property on the A class:
class A {
public int Id { get; set; }
public int BId {get; set;}
[ForeignKey("BId")] //can do this in the fluent API instead
public virtual B B { get; set; }
}
Then you can just use the class A in the mapping with no need to load the B entity
I would like to do a LINQ query that returns all of the records for the Parent table, and includes the Child, if applicable. I know I can do a LINQ join with DefaultIfEmpty(), but then I must output a ViewModel. I'd like to get an IQuerable<Parent> of the actual Parent Class.
So, if I have these classes:
public class Parent
{
[Key]
public int ParentId {get; set;}
public string ParentName {get; set;}
public int? MyChildId {get; set;}
[ForeignKey("MyChildId")]
public virtual Child MyChild {get; set;}
public bool IsActive {get;set;}
}
public class Child
{
public int ChildId {get;set;}
public string ChildName {get;set;}
}
In LINQPad, if I do this:
var results = db.Parent.Where(ra => ra.IsActive);
results.Dump();
I get 111 records.
If I do this:
var results = db.Parent.Where(ra => ra.IsActive);
var results2 = (from r in results
select new
{
ParentId = r.ParentId,
ParentName = r.ParentName,
MyChildId = r.MyChildId
});
results2.Dump();
I also receive 111 records.
But if I do this:
var results = db.Parent.Where(ra => ra.IsActive);
var results2 = (from r in results
select new
{
ParentId = r.ParentId,
ParentName = r.ParentName,
MyChildId = r.MyChildId,
IsActive = r.IsActive,
MyChildName = r.MyChild == null ? null : r.MyChild.ChildName
});
results2.Dump();
I only get 50 records. These are the 50 Parent records that have a child. If they do not have a child, they don't come back.
The SQL generated looks like this:
SELECT
[Extent1].[ParentId] AS [ParentId],
[Extent1].[ParentName] AS [ParentName],
[Extent1].[IsActive] AS [IsActive],
[Extent2].[ChildName] AS [ChildName]
FROM [dbo].[Parent] AS [Extent1]
INNER JOIN [dbo].[Child] AS [Extent2] ON [Extent1].[MyChildId] = [Extent2].[ChildId]
WHERE [Extent1].[IsActive] = 1
How can I get a resultset that includes all 111 Parent records, even if they have no child, but does include the Child elements, if they are there?
UPDATE
So, I may have lied a bit. I posted the above for simplicity sake, but just in case it helps, here is a closer sample of what the code does:
public class Parent
{
[Key]
public int ParentId {get; set;}
public string ParentName {get; set;}
public int? MyChildId {get; set;}
[ForeignKey("MyChildId")]
public virtual Child MyChild {get; set;}
[ForeignKey("MyChildId")]
public virtual StepChild MyStepChild {get; set;}
public bool IsActive {get;set;}
}
public class Child
{
public int ChildId {get;set;}
public string ChildName {get;set;}
}
public class StepChild
{
public int StepChildId {get;set;}
public string StepChildName {get;set;}
}
Sometimes it's hard to tell what's going on behind the scenes of EF, and you can encounter some non-obvious behaviors, what I usually do in such cases - is check the actually generated SQL query, and tweak the LINQ query until it is logically equivalent to the query I expect.
This is not the best approach as it is dependent on implementation details, that can change, but sometimes it is the only way to overcome a EF bug.
You can use ObjectQuery or EF logging and interception of DB calls to get to actual SQL query
Your foreign key is non nullable by default (or required), so you need to tell the EF that it should be optional. To make it you need to override the following modelBuilder method:
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
and configure your Entity foreign key:
modelBuilder.Entity<Parent>().HasOptional(e => e.MyChild).WithMany();
Details you can look here: http://blog.staticvoid.co.nz/2012/7/17/entity_framework-navigation_property_basics_with_code_first
You need two separate FK properties one int? personAssigneeId and another int? organizationAssigneeId. These FKs are pointing to two completely different entities. EF is not able to work properly if you reuse the same FK for two separate entities, it needs a FK per entity.
I'm new working with EF and a have this scenario:
Classes:
public class Step
{
public int ID { get; set; }
public string name { get; set; }
}
public class Workflow
{
public int ID { get; set; }
public int stepID { get; set; }
public int nextStepID { get; set; }
public virtual Step Step
}
What I want to know is if have a way to get "name" from class Step based on stepID and nextStepID.
I know that I can do that
var result = (from Workflow in db.Workflow
join Step in db.Step on Workflow.stepID equals Step.ID
join nextStep in db.Step on Workflow.nextStepID equals nextStep.ID
select new
{
nameStep = Step.name,
nameNextStep = nextStep.name
}
).ToList();
but this way i'm not retrieving a Workflow entity.
I'm wondering if is possible to do something like that "automatically" using EF to retrieve a Workflow entity with Step and Next Step name.
I hope that's clear.
Thanks in advance
You can include the WorkFlow entity in the anonymous type like this:
select new
{
Workflow = Workflow,
nameStep = Step.name,
nameNextStep = nextStep.name
}
You might want to consider modeling the Workflow entity in such a way that it has two navigational properties to Step. One for the stepID foreign key and one for the nextStepID foreign key. This will make your queries simpler. Take a look at this question.
Alright, so I'm using Entity Framework, code-first approach. I've got the following entity classes:
class EntityA
{
public int EntityAId { get; set; }
public virtaul ICollection<EntityB> Bs { get; set; }
}
class EntityB
{
public int EntityBId { get; set; }
public bool Foobar { get; set; }
public virtual EntityA A { get; set; }
}
Given a DbSet<EntityA>, I'm trying to figure out how to query for all EntityA's where any of the EntityB's in Bs has Foobar equal to true.
How can I do this query, using EF fluent query API? Thanks!
var entities = dbSet.Where(m => m.Bs.Any(b => b.Foobar == true).ToList();
Should do it for you. Basically - give me all EntityAs that has any child EntityB where foobar equals true. For more information look into Linq and Linq to Entities.
For your comment:
var dbSet= your dbset of EntityB
var id = the id of the EntityB you're querying with
var entities = dbSet.Where(m => m.A.Bs.Any(b => b.EntityBId == id)).Select(m => m.A).ToList();
So again, lets sound it out - give me every EntityA from a collection of EntityBs, where the EntityB's A navigation prop contains any EntityB with an id equal to a given id. Since you're querying a set of EntityBs, you'll have to select that entity's A. Geeze this is hard to say; too many as and bs.