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;
Related
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
I have the following:
public class SomeClass {
public Guid Id { get; set; }
public string Name { get; set; }
// Instead of having
public IEnumerable<Tag> Tags { get; set; }
// I want something like this
public IEnumerable<string> Tags { get; set; }
// more properties here
}
public class Tag {
public Guid Id { get; set; }
public string Name { get; set; }
// I put this here just to show you what I want,
// normally EF Core will generate this for me
public Guid SomeClassId { get; set; }
}
Is it possible to create the above scneario?
I know a good and maybe even better way to do this would be a Many-To-Many Relationship. But it would be neat to just add a new tag to the list and let EF take care of the rest of it.
I know there is Value Conversions, but I can't figure out if it is possible to apply it in this scenario. If I recall correctly you can do something like this in EF 6 with some custom mapping, but I don't see any version to do it in EF-Core.
Thanks in advance.
So I have a class with a static method that uses EF to retrieve certain set of mailing lists and maps to the class.
public static List<MailingList> GetMailingListsForUser(IUsersAccess user, IProspectorDataSource db )
{
return db.MailingLists.Where(x => x.UserID == user.UserID).ToList()
.Select(y => new MailingList(y, db) ).ToList();
}
Now though I have a proc that will return the MailingList plus some extra stuff. I don't want to add these extra columns (which will be used in other sections and areas of functionality) to this class. What is the best way to address this?
I am thinking a Factory Pattern that will generate a different class that implements different contracts (interfaces) based on whats needed. Going to try implement it and will post code/working when completed.
Was wondering what other people have done in instances like this and if there are any better ways to address this.
Edit: (some extra information to help people understand what I mean).
public class MailingList
{
public int MailingListID { get; set; }
public string Name { get; set; }
public string Comments { get; set; }
public List<string> Tags { get; set; }
public int UserID { get; set; }
public System.DateTime DateCreated { get; set; }
public string CreatedBy { get; set; }
public System.DateTime LastModified { get; set; }
public string ModifiedBy { get; set; }
public List<MailingListAddress> MailingListAddresses { get; set; }
That is the definition of an object that we return. Now there is a new instance where I am going to return some extra columns from a proc and map to MailingList. So I could just add the properties to here but the issue is MailingListAddresses will be null as they will not be returned by the stored proc. So is there a way to map to specific properties and not have to return null for MailingListAddresses to the front end every time.
This was fixed by a senior developer who ended up going with the factory pattern. I will add the code when I get back to work :)
I have a class, NewsItem, and I would like to create a list of child objects IList using entity framework and lazy loading.
My NewsItem class is straight forward:
public class NewsItem
{
public int ID { get; set; }
public DateTime PublicationDate { get; set; }
public DateTime LastUpdated { get; set; }
public int? TopPictureID { get; set; }
public virtual Picture TopPicture{get; set;}
public string Headline { get; set; }
public string StandFirst { get; set; }
public string Body { get; set; }
public IList<DirectComment> Comments { get; set; }
}
The comments class is based upon a table that can have comments for other article types (e.g. PR, blogs, features) as well as NewsItems:
public class DirectComment
{
public int ID { get; set; }
public DateTime Published { get; set; }
public string Comment { get; set; }
public bool Live { get; set; }
public int ArticleID { get; set; }
public string ArticleType { get; set; }
}
I am unsure as to how I would get all comments for a news item, where I would have a Where statement that specifies the DirectComment.ArticleType as "newsitem" and ArticleID of, for example, 1000 - that will lazy load and also will not create an issue for Dependency injection.
I could just put something akin to the following in the NewsItem.Comments Get statement:
public class NewsItem
{
[...]
[NotMapped]
private IList<DirectComment> comments;
[NotMapped]
public IList<DirectComment> Comments
{
get
{
if (null == comments)
{
IDirectCommentRepository dcRepository = new DirectCommentRepository();
comments = dcRepository.DirectComments.Where(dc => dc.ArticleID == this.ID
&& dc.ArticleType == "news").ToList();
}
return comments;
}
}
}
...however, that wouldn't be great for DI as it means that I will have to hard-code the "New DirectCommentRepository()" and it will be an issue when it comes to Unit Testing. So, is it possible for me to get around the problem?
You can simply inject the repository usind DI. You can use constructor injection or property injection or whichever you want. In this way, you can modify the dependency for unit testing.
If your concern is about instancing the repository when you don't need to use it, there are at least two solutions:
depending on your DI framework, it's possible that it supports lazy instancing (you can see this to understand what I'm speaking about: Unit.MVC4’s lazy<T> is not working in ASP.NET MVC 4 app)
if you don't want to use that solution, or your DI framework doesn't support it, you can inject a factory that provides instances of the repository. So, the repository are only instanced in the code path that need it. To make this feasible your factory can't be static.
In both solutions, you can inject a fake for your unit tests.
I've spend several days now, trying to solve this problem. While making a simple project to exemplify my problem, I stumbled upon a possible solution. So, this is sort of a double question.
But first, a little background info:
I just started using Entity Framework 4.1 (EF) and Code First to create the models for my ASP.NET MVC project. I need some models similar to this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class Family
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Father> Fathers { get; set; }
public virtual ICollection<Mother> Mothers { get; set; }
}
public class Mother
{
public int ID { get; set; }
public string Name { get; set; }
public int FamilyID { get; set; }
public virtual ICollection<Child> Children { get; set; }
public virtual Family Family { get; set; }
}
public class Father
{
public int ID { get; set; }
public string Name { get; set; }
public int FamilyID { get; set; }
public virtual ICollection<Child> Children { get; set; }
public virtual Family Family { get; set; }
}
public class Child
{
public int ID { get; set; }
public string Name { get; set; }
public int MotherID { get; set; }
public int FatherID { get; set; }
public virtual Mother Mother { get; set; }
public virtual Father Father { get; set; }
}
}
And the DbContext:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
namespace TestApp.Models
{
public class TestContext : DbContext
{
public DbSet<Family> Families { get; set; }
public DbSet<Mother> Mothers { get; set; }
public DbSet<Father> Fathers { get; set; }
public DbSet<Child> Children { get; set; }
}
}
(Please excuse the lame example, that's what my Friday fried brain was able to come up with.)
A family can have several mothers and several fathers. And a child has a mother and a father. I checked with one of the .NET gurus at my work, who agreed that there is nothing extraordinary in this. At least as far as we can see.
But when I run the code, I get this Exception:
System.Data.SqlServerCe.SqlCeException: The referential relationship will result in a cyclical reference that is not allowed. [ Constraint name = Mother_Family ]
I do see the cycle: Family - Mother - Child - Father - Family. But if I created the database tables myself (which I prefer not to, that's what I like about Code First) it would be a perfectly valid data structure, as far as I can tell.
So, my first question is: Why is this a problem when using code first? Is there a way to tell EF how to properly handle the cycle?
Then, as I write initially, while creating a simple project to exemplify my problem, I incidentally stumbled upon a possible solution. I simply forgot some of the properties when defining my models. For clarity in the following example, instead of removing them, I've commented out the parts of the models I forgot:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class Family
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Father> Fathers { get; set; }
public virtual ICollection<Mother> Mothers { get; set; }
}
public class Mother
{
public int ID { get; set; }
public string Name { get; set; }
// public int FamilyID { get; set; }
public virtual ICollection<Child> Children { get; set; }
public virtual Family Family { get; set; }
}
public class Father
{
public int ID { get; set; }
public string Name { get; set; }
// public int FamilyID { get; set; }
public virtual ICollection<Child> Children { get; set; }
public virtual Family Family { get; set; }
}
public class Child
{
public int ID { get; set; }
public string Name { get; set; }
// public int MotherID { get; set; }
// public int FatherID { get; set; }
public virtual Mother Mother { get; set; }
public virtual Father Father { get; set; }
}
}
So, removing these SomethingID reference properties seems to solve my problem. As you can see in the controller of the sample project I'm linking to in the end of this post, I'm still able to cycle all the way around and do stuff like mothers.First().Family.Fathers.First().Children.First().Mother.Family.Name without any problems. But all tutorials and examples about EF and Code First modeling I've been looking at (e.g. this one by Scott Guthrie) include these properties, so it feels wrong not to use them.
And so, my second question is: Will there be any drawbacks and problems I haven't discovered yet doing this?
Download example project here: http://blackfin.cannedtuna.org/cyclical-reference-test-app.zip, and open TestSolution.sln. The properties are commented out in the example project. Uncomment the lines in TestModels.cs to add the properties, resulting in the cyclical reference exception.
NB: The solution is creating and seeding a SQL CE database located at c:\TestApp.sdf
Update, December 2011:
I never solved this problem technically, but I quit my job and found another job where I don't have to use Microsoft technologies. That sort of solved my problem :)
As the tech support at the old place used to write when fixing issues: "A workaround or solution has been provided".
But if I created the database tables myself (which I prefer not to,
that's what I like about Code First) it would be a perfectly valid
data structure, as far as I can tell.
This is something you should double check. The exception comes directly from the database and not from Entity Framework. It's likely that also a table structure with the same constraints created by hand will be invalid. Keep in mind that your foreign key properties Mother.FamilyID, Father.FamilyID, Child.MotherID and Child.FatherID are not nullable, so they represent required relationships and the corresponding columns in the database are also not nullable.
When you remove all these properties from your model classes your relationships become suddenly optional because the navigation properties can be null. This is another model now since the FK columns in the DB can be nullable! Apparently this is an allowed model.
If you want to have still foreign key properties in your model which represent optional instead of required relationship you can use nullable types: public int? FamilyID { get; set; }, public int? MotherID { get; set; }, etc.
This is a known problem and you're not the first to bump into it. From what I've heard they are working on a better solution in the upcoming version of WCF, however for the time being from my experience you are much better off creating DataContracts that represent the data to be sent over the wire thereby changing the data structure to remove the cyclic reference.
I know it's a pain, but there are other benefits to be had in that you most likely will want to make other changes to structures that your clients consume anyway instead of letting them play with the objects as they exist in your db
I had much the same problem however I solved it using the advice in this answer Entity Framework Code First - two Foreign Keys from same table which works better than changing the type of the key columns to optional.