Populate relational objects in Entity - c#

I have a class that looks like this :
public partial class Defect
{
public int DefectID { get; set; }
public string Title { get; set; }
public virtual DefectStatus DefectStatus { get; set; }
public virtual Developer Developer { get; set; }
public virtual Project Project { get; set; }
}
When I call this :
var defect = db.Defects.Find(id);
How can I make it fill Project with the relational data from the Project table?
Currently I am doing the following defect.Project to populate defect.Project
var defect = db.Defects.Find(id);
defect.Project = db.Projects.Find(defect.ProjectID);
But I want to know if there is a better way to accomplish the same thing?

If you are still inside the db context when you ask for the Project, then (because you have marked the property Virtual), Project will be lazy loaded. If you are outside the db context, then you need to load it (as you are doing) while in the context.
However, you can eager load the Project entity by not using the Virtual keyword or by using Include in your query:
db.Defects.Include("Project").Where(d => d.DefectId.Equals(id));
This looks like the best reference for loading entities.

Related

Retrieve from DB and Include Multiple ICollections

I'm working with EF6. I have a module with multiple ICollections. My solution to retrieve the lists of objects is similar but I find it dumb, as I need to rewrite this on all the pages where I need IEnumerable<BookModel> GetAllBook.
IEnumerable<BookModel> GetAllBook = DBContext.BookModels.Include(x => x.AssociatedNames).Include(e => e.BlogModel);
I read several topics on this but these stood out. From what I understood, the answer is written in the DbContext.cs with the DbSets. But does the BookModule have a complete list of example authors? Without the need of including another time?
Include several references
I also read
Why does EF Core One-to-Many relationship collection return null?
public class BookModel
{
[Key]
public int BookModelID{ get; set; }
public virtual ICollection<AssociatedNames>? AssociatedNames { get; set; }
public virtual List<BookModel>? relatedSeries { get; set; }
public virtual List<BookModel>? RecommendedBookModels { get; set; }
public virtual ICollection<AuthorModel>? Authormodels { get; set; }
public virtual ICollection<ArtistModel>? ArtistModels { get; set; }
public virtual ICollection<VoiceActorModel>? VoiceActors { get; set; }
public virtual ICollection<GenresModel>? GenresModels { get; set; }
public virtual ICollection<TagModel>? TagsModels { get; set; }
}
My question is there a way for my bookModel have the complete lists of objects without needing to use Include again, and again.
Best regards
What you need in this cas is the AutoInclude feature introduced with EF6 , so You will have to go into the OnModelCreating Method and add the following lines ( you update that to your use case , depends on which related entities you want to be autoIncluded ):
modelBuilder.Entity<BookModel>().Navigation(e => e.Authormodels).AutoInclude();
modelBuilder.Entity<BookModel>().Navigation(e => e.Artistmodels).AutoInclude();
and if , for a specific cas you need only the books , and you want to get rid of the autoIncludes , then us can use the IgnoreAutoIncludes feature like below :
var books = context.BookModels.IgnoreAutoIncludes().ToList();
Fore more details about this you can look up this documentation or this video

Model is not fully loaded out of DB after save from EF-Core

I have a EF-Core Code-First apporach. Im Saving a HolderModel into a Database which contains a ID and a List of Models.
On Saving everything works fine. The Struktur is correct and all data is in the Database. But if i load the data back into my code, the List of Models is gone.
Im a bit confused as usally EF did everything by him self.
Am i missing something for EF-Core ?
Here is the codesnippet:
DB-Context:
public DbSet<FinancialStateHolderModel> States { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseSqlServer(
#"Server=.\;Database=Stock;User Id=dbuser;Password=dbuser");
builder.EnableSensitiveDataLogging(true);
}
HolderModel:
public class FinancialStateHolderModel
{
[Key]
public String Symbol { get; set; }
public List<FinancialStatementModel> Financials { get; set; }
}
Models:
public class FinancialStatementModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime Date { get; set; }
}
Please check Loading Related Data in Entity Framework.
You're looking for
Eager loading - the related data is loaded from the database as part
of the initial query
In your case(example not exact syntax because I don't know what your call looks like)
should be context.FinancialStateHolders.Include(x=> x.FinancialStatements)

Lazy loading not working when adding detached entity

I have an ASP.NET MVC 4 application using Entity Framework 5 under .NET 4.5. The problem I'm having is that when I insert a detached entity that was created on the front-end, the lazy loading is not working.
Here is my code to add (or update):
public static int PersistMergeEntity(EntityTwo entityTwo)
{
int entityId;
using (var _db = new EntityDb())
{
if (_db.EntityTwo.Any(e => e.EntityTwoId == entityTwo.EntityTwoId))
{
_db.Entry(entityTwo).State = EntityState.Modified;
}
else
{
_db.EntityTwo.Add(entityTwo);
}
_db.SaveChanges();
//_db.Entry(entityTwo).Reference(e => e.EntityOne).Load();
entityId = entityTwo.EntityOne.EntityId;
}
EntityBo.UpdateData(entityId);
return entityTwo.EntityTwoId;
}
Here are my entities:
public class EntityTwo
{
[Key]
[ForeignKey("EntityOne")]
public int EntityTwoId { get; set; }
public Decimal NbValue { get; set; }
public virtual EntityOne EntityOne { get; set; }
}
public class EntityOne
{
[Key]
[ForeignKey("EntityTwo")]
public int EntityOneId { get; set; }
[ForeignKey("Entity")]
public int EntityId { get; set; }
public CsMonthDomain CsMonth { get; set; }
public int NbYear { get; set; }
public Decimal NbValue { get; set; }
public virtual Entity Entity { get; set; }
public virtual EntityTwo EntityTwo { get; set; }
}
And Entity is another entity that I need to do calculation every time I update or add EntityTwo.
The code works when the commented line is uncommented. But if it is the way shown up there, lazy loading will not work and I'll get a null Exception.
Lazy loading is set to true and the entities are, supposedly, correct, since it works when I explicitly load the navigation property.
I'm sorry about the names, but unfortunately I cannot post the real code ;(
Lazy loading does not work because the entityTwo you pass into the method is (most likely) not a dynamic proxy which it has to be in order to make lazy loading work. The instance is probably created outside the method using entityTwo = new EntityTwo();. To create a proxy of an entity you would need a context instance available and then use
entityTwo = _db.EntityTwos.Create();
In my opinion using explicit loading (your commented line) is the best solution in this situation. It has the same costs of querying the database once per navigation property like lazy loading would have plus the additional benefit over lazy loading that you could project a selection of properties you only need from the related entity, for example:
entityId = _db.Entry(entityTwo).Reference(eTwo => eTwo.EntityOne).Query()
.Select(eOne => eOne.EntityId)
.Single();

Where did the overload of DbQuery.Include() go that takes a lambda?

I just declared some code-first models for a new project that uses EntityFramework.
public class BlogEntry
{
public long Id { get; set; }
public long AuthorId { get; set; }
public DateTime PublishedStamp { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public virtual User Author { get; set; }
}
public class User
{
public long Id { get; set; }
public string Email { get; set; }
// ...
}
class BlogDb : DbContext
{
public DbSet<BlogEntry> Entries { get; set; }
public DbSet<User> Users { get; set; }
}
Now suppose I want to retrieve the 10 most recent blog entries:
var entries = new BlogDb().Entries.OrderByDescending(...).Take(10).ToList();
The problem now is that accessing entry.Author will cause another database query. You wouldn’t want a separate such query for every blog entry. Now, it is my understanding that the purpose of Include is exactly this case, so I can say:
var entries = new BlogDb().Entries.Include(e => e.Author).(...).ToList();
However, that method doesn’t seem to exist. There is only an Include(string), like this:
var entries = new BlogDb().Entries.Include("Author").(...).ToList();
but this is annoying because it’s not compile-time checked and will be missed by the rename refactoring. Surely the version with the lambda is the “correct” approach.
Where did that method go? Is it no longer included in EntityFramework?
(I know that I can write an extension method for myself to achieve this, so you don’t have to. I’d just like to know whether I’m missing something.)
using System.Data.Entity;
It's in EF v4.1 and above, but you need a reference as it is an extension method.
Edit (thanks to #EastonJamesHarvey)
If using EF Core the import should be:
using Microsoft.EntityFrameworkCore;

Entities Architecture

Using VS2010, .NET4.0, MVC3, EF4.1 Code-First
I have this POCO entities:
public class XBLContent
{
[Key]
[StringLength(36, ErrorMessage="Must have 36 characters")]
[Required(ErrorMessage="Must have a unique GUID")]
public string GUID { get; set; }
public int Price { get; set; }
public float FileSize { get; set; }
public virtual ICollection<XBLRegionalContent> RegionalInfo { get; set; }
public string RelatedGameId { get; set; }
[ForeignKey("RelatedGameId")]
public virtual XBLContent RelatedGame { get; set; }
}
public class XBLRegionalContent
{
[Key, Column(Order = 0)]
public string ContentId { get; set; }
[ForeignKey("ContentId")]
public virtual XBLContent Content { get; set; }
[Key, Column(Order = 1)]
public string RegionId { get; set; }
[ForeignKey("RegionId")]
public virtual XBLRegion Region { get; set; }
public string Name { get; set; }
}
public class XBLRegion
{
[Key]
[StringLength(5, ErrorMessage="ID must have 5 characters")]
[Required]
[RegularExpression(#"[a-z|A-Z]{2}-[A-Z|a-z]{2}")]
public string ID { get; set; }
public string Country { get; set; }
public string Language { get; set; }
}
Relationships:
One XBLContent has many XBLRegionalContent;
One XBLContent can be related to another XBLContent(most of them are not);
One XBLRegionalContent has one XBLContent and one XBLRegion;
One XBLRegion has many XBLRegionalContent;
The Context objetc is really simple:
public class XBLContentContext : DbContext
{
public DbSet<XBLContent> XBLContents { get; set; }
public DbSet<XBLRegionalContent> XBLRegionalInfos { get; set; }
public DbSet<XBLRegion> XBLRegion { get; set; }
public XBLContentContext() : base("XBLToolsDB")
{
}
}
I'm using XBLContent as my main business object and maybe that is not the best idea. I think there is something wrong with the architecture I designed because I'm having trouble to send information to the View and filter, sort, etc.
Now, I'm using Telerik grid and when I try to sort by a navigation property field I get an error saying that "No property or field exist". Maybe I should not use XBLContent as my main business object, or create a ViewModel containing all needed fields and send it to the View. Or create one single entity that splits into two EF tables(I don't know if that is possible or how to achieve that).
I'm just padawan in .NET and need some Jedi Masters advice.
I need contents that can have multiple translations.
How to best achieve this goal?
this should fix your problem.
http://weblogs.asp.net/manavi/ A great resource for beginners and i can see you have used a lot of annotations ,so a little bit of fluent api would make your concepts stronger.
I'm assuming you're using the Telerik MVC Extensions here, but if you are using a different product please let me know and I'll re-answer accordingly :)
In regards to the Grid what kind of binding are you utilizing? If you are using regular server or ajax binding then you might run into some issues when binding to a navigational property, as by default these bindings only work with primitive (int, string etc.) types. However, there is such a thing as custom binding which allows you to take full control over paging/sorting/filtering. I believe this could account for why you are getting this error, as the automatic LINQ expressions cannot find the specific field you are looking for. Here are two demos (which have source code for both WebForms and Razor ViewEngines) that can help with setting up custom binding. It's just a little more work than the automatic binding, but should still work (note that these examples are using Razor):
Ajax Binding
Server Binding
The added benefit here is that you get to control everything on your own, which can be quite nice in somewhat more complex scenarios. If you're already using custom binding, and/or if the links there do not help let me know. It could also be helpful to have the code for the Telerik Grid.
I've resolved these kinds of issues by normalizing the results like:
from r in ctx.XBLContents
select new
{
r.Guid,
RelatedGuid = r.RelatedGame.Guid
};
Essentially creating an anonymous classes that is more denormalized has worked for me to work around these kinds of issues, where the results denormalizes those navigational properties too.
HTH.

Categories