I saw a lot of post showing how to perform a query within Entity Framework to retrieve master details data, like this:
IQueryable<myobj> foo = _context.Foos.Include(x => x.FooDetails).Where(x => x.Id == fooId);
But I have to manage an harder case. A master details where every detail has its own details.
Something like:
Foo --> FooDetails --> FooDetailsInfo
Is this possible? If yes, how? Of course the dumb solution exists and it is use a loop. Is there a smarter way to reach this goal?
I tried to edit the line code
IQueryable<myobj> foo = _context.Foos.Include(x => x.FooDetails).Where(x => x.Id == fooId);
but I didn't write anything useful.
Yes, it is possible. After Include you can call ThenInclude
var foo = _context.Foos
.Include(x => x.FooDetails)
.ThenInclude(fd => fd.FooDetailsInfo)
.Where(x => x.Id == fooId);
Related
I'm modelling a 3rd party database using Automapper 8 and EF 6.
One of my DTO classes needs to use a Where clause on an association to locate the correct record.
// Community table is mapped and working.
// Mapping breaks when mapping dest.Subjects
cfg.CreateMap<Person, PersonDto>()
// snip many mappings
.ForMember(dest => dest.Id, act => act.MapFrom(src => src.ID))
.ForMember(dest => dest.UserName, act => act.MapFrom(src => src.Community.NetworkLogin))
.ForMember(
dest => dest.Subjects,
act => act.MapFrom(
src => src.Community.StudentClasses.Where(
subject => subject.Year == CurrentSemester.Year && subject.Semester == CurrentSemester.Semester)))
.ForMember(
dest => dest.Contacts,
act => act.MapFrom(
src => src.Community.Contacts.Where(
contact => Contact.UseThis).Select(contact => contact.ContactDetails)));
This code works in production, but I'd really like to Unit Test this model. Running a simple test (get all records in the Mock) I'm hit with a NullReferenceException when it tries to access the Community.StudentClasses object.
I found this answer relating to NullReferenceExceptionexceptions and AutoMapper, which helped me fix the rest of the references in this config, but I'm still having issues with this one. The test works when I remove the Community.StudentClasses mapping.
I'm mocking objects using code similar to:
public static Person Person19788 =>
new SchoolContact
{
ID = 19788,
NetworkLogin = "username",
// Tried various creation methods
// StudentClasses = new List<StudentClass> {new StudentClass()},
// StudentClasses = new List<StudentClass> {new StudentClass {Year = 0, Semester = 0}},
StudentClasses = null,
StudentContacts = null,
Address = Address19788
};
CurrentSemester has been checked, and returns valid non-zero values for Year and Semester.
The strange thing is that the Contacts mapping works fine, even with null values. So I assume that I've broken my Subjects mapping somewhere along the line, but I'm unsure where else to look.
It turns out that the problem was with my Subjects mapping after all.
The top-level associations were mapped correctly, however the lower-level associations were not. (I didn't include these mappings because a) I didn't think about them, and b) there's only so much code that anyone would be willing to wade through).
After fixing up the w > x > y > z mappings everything is working as expected. I thought I'd exhausted all options before posting this question. Lesson learned: don't post to SO until you've slept on it and taken a fresh look at the code the next day.
I've a linq query :
var NextWeekDate = DateTime.Now.AddDays(7);
var BirthData = db.EmployeeMasterAs
.Where(x => x.Emp_BirthDate >= CurrentDate)
.Select(x => new { x.Emp_BirthDate,
DaysRemaining = (NextWeekDate - x.Emp_BirthDate).Value.TotalDays
})
.OrderBy(x => x.Emp_BirthDate)
.ToList();
Note the element in Select() method, DaysRemaining = (NextWeekDate - x.Emp_BirthDate).Value.TotalDays, I want to get the difference between dates in days and save that to DaysRemaining, this query is not working and the exception that it throws :
DbArithmeticExpression arguments must have a numeric common type.
I don't know exactly how to achieve this, Any Ideas?
I think that LinqToSql does not support DateTime.Subtract. But you can use the preexisting function SqlMethods.DateDiffDay (https://msdn.microsoft.com/en-us/library/bb468730(v=vs.110).aspx)
Edit: SqlMethods is only intended for SQL Server. DbFunctions is the helper class to pick regardless of the database type.
Yep, Got it, So here is how it goes :
Performing arithmetic operations with Dates and Times is not supported in EF. EntityFramework cannot convert your code to SQL. Instead of that you can use DbFunctions.DiffDays( startExpression, endExpression) method:
db.EmployeeMasterAs
.Where(x => x.Emp_BirthDate >= CurrentDate)
.Select(x => new { x.Emp_BirthDate,
DaysRemaining = DbFunctions.DiffDays(x.Emp_BirthDate,NextWeek)
})
.OrderBy(x => x.Emp_BirthDate)
.ToList();
Furthermore : DbFunctions Functions methods are called canonical functions. And these are a set of functions, which are supported by all Entity Framework providers. These canonical functions will be translated to the corresponding data source functionality for the provider. Canonical functions are the preferred way to access functionality outside the core language, because they keep the queries portable.
I'm exporting a method using MEF with the attribute [Export] and I need to consume this method using the Container (obtaining the method using GetExports).
GetExports returns an ExportedDelegate object that I have no idea how to extract the MethodInfo from.
Inspecting with the debugger I see it as a private property and I'm tempted to extract it using reflection but it doesn't feel like the right way of doing this.
Any ideas?
This problem is different than this one. I'm not trying to use [Import], I have to obtain and consume the method from the Container.
Alright guys so that was a tricky one but I'm leaving here as a reference.
All you have to do is to cast the value returned from MEF to a ExportedDelegate and call CreateDelegate the right way:
This sets the Import we want:
var importDefinition = new ImportDefinition(e => true, obj.GetType().FullName, ImportCardinality.ZeroOrMore, false, false);
var objectsWithMethods = container.GetExports(importDefinition)
.Where(x => x.Value is IYourInterface)
.Select(x => x.Value)
.ToList();
This gets the methods of the objects found above (iterate objectsWithMethods in a foreach using objectsWithMethod):
var endPointsImportDefinition = new ImportDefinition(e => true, objectsWithMethod.GetType().FullName, ImportCardinality.ZeroOrMore, false, false);
var endPoints = container.GetExports(endPointsImportDefinition)
.Where(x => x.Value is ExportedDelegate)
.Select(x => x.Value)
.ToList();
And finally to get MethodInfo (which allows you to run the method) you use:
var endPointMethod = (endPoint as ExportedDelegate).CreateDelegate(typeof(Delegate)).GetMethodInfo();
What also could be:
var endPointMethod = (endPoint as ExportedDelegate).CreateDelegate(typeof(Delegate)).Method;
Hope it helps anyone!
Mocked setup below (the GenerateTrades() and other methods in ContextFactory are just returning a List AsQueryable with sample data):
_trades = ContextFactory.GenerateTrades();
_hedges = ContextFactory.GenerateHedges();
_exposures = ContextFactory.GenerateExposures();
_ctx = new Mock<FxContext>();
var fakeTrades = new Mock<DbSet<Trade>>();
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.Provider).Returns(_trades.Provider);
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.Expression).Returns(_trades.Expression);
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.ElementType).Returns(_trades.ElementType);
fakeTrades.As<IQueryable<Trade>>().Setup(m => m.GetEnumerator()).Returns(_trades.GetEnumerator());
var fakeHedges = new Mock<DbSet<Hedge>>();
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.Provider).Returns(_hedges.Provider);
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.Expression).Returns(_hedges.Expression);
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.ElementType).Returns(_hedges.ElementType);
fakeHedges.As<IQueryable<Hedge>>().Setup(m => m.GetEnumerator()).Returns(_hedges.GetEnumerator());
var fakeExposures = new Mock<DbSet<Exposure>>();
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.Provider).Returns(_exposures.Provider);
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.Expression).Returns(_exposures.Expression);
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.ElementType).Returns(_exposures.ElementType);
fakeExposures.As<IQueryable<Exposure>>().Setup(m => m.GetEnumerator()).Returns(_exposures.GetEnumerator());
_ctx.Setup(c => c.Trades).Returns(fakeTrades.Object);
_ctx.Setup(c => c.Hedges).Returns(fakeHedges.Object);
_ctx.Setup(c => c.Exposures).Returns(fakeExposures.Object);
Part of test code looks like:
_sut = (from x in _ctx.Object.Hedges
where x.Id == ContextFactory.s_hedge01Id
select x).FirstOrDefault();
_ctx.Object.Hedges.Attach(_sut);
_ctx.Object.Entry(_sut).Collection(x => x.HedgedTrades).Load();
On the last line I get an exception:
{"Member 'Load' cannot be called for property 'HedgedTrades' because the entity of type 'Hedge' does not exist in the context. To add an entity to the context call the Add or Attach method of DbSet<Hedge>."}
I have verified that in fact the _sut Hedge is actually an instance of a Hedge (not null or a stub) and as the code seems to indicate, I have attached the Hedge to the context explicitly (though I would think the query should bring the object into the context automagically). Am I missing something?
It seems like here in your test you are mixing two separate approaches. Error you received states that you are trying to access DbContext inherited logic, but it is mocked. If you want to perform your unit tests against database with use of FxContext then do not mock it. If you want test other part of software then you should mock interface that FxContext should implement. This will enable you to fullfil dependency injection principle in your code which will help you then organize your test in more predictable way.
I would like to create a more structured approach to loading the needed entity-tree:
I need a serious amount of data, so I'm doing this using type-safe Includes (just a normal Include but with Lambda's) as shown here.
As I said, I need a lot of data, basically a whole entity tree under 1 parent item.
Now, I could do this doing something like:
context.House
.Include(x => x.Doors)
.Include(x => x.Doors.FirstOrDefault().Joint)
.Include(x => x.Doors.FirstOrDefault().Joint.FirstOrDefault().JointCategory)
.Include(x => x.Doors.FirstOrDefault().Joint.FirstOrDefault().JointCategory.JointType)
.Include(x => x.Windows)
// ... same thing
.Include(x => x.Roof)
// ... same thing
As you can see, this line filled with includes can get quite huge. This is in fact a very simplified sample of the actual code (which doesn't include houses btw)
So what I would like to do is creating methods, responsible for its branch in the tree. Where the method can accept the object query and include the child, and in its turn, call the "child-loader methods". Also, the parent shouldn't matter, as long as it has a property with the type of the child.
This probably does not make much sense so:
public void LoadHouse(int id)
{
// ...
ObjectQuery<House> query = context.House;
// and now?
LoadDoors(query, x => x.Door);
}
public void LoadDoors<T>(ObjectQuery<T> query, ..?..)
{
// ... ?
LoadJoints(...)
}
And so on. But I can't really get my head around it... There's a missing link between the incoming query and calling the child methods.
Has anyone done something like this? Or could anyone give me some pointers?
Try something like this instead:
query = LoadDoors(query, x => x.Door);
Where LoadX returns the result of calling Include.