I have a class Mailout with a Status that looks like this:
public class Mailout
{
public int Id {get; set; }
public string Name {get; set; }
public MailoutStatus Status { get; set; }
}
public class MailoutStatus
{
public int Id { get; set; }
public string Name { get; set;}
}
When I insert Mailouts and set the Status property, they are inserted correctly. When I fetch them, Status is always null. Since I don't have (and don't want) the status ID on my Mailout class, I have no way to retrieve it after-the-fact. How do I tell EF to populate this field eagerly, rather than lazily?
I'm hoping I can set something up in OnModelCreating() since I want this behavior all the time, not as an option that I can use sometimes by manipulating my LINQ-to-Entities queries.
You need to make your navigation properties virtual.
There is no such option in the ModelBuilder to configure an automatic eager loading of navigation properties in each query. You have to specify it query by query. As a workaround you could encapsulate eager loading in some method or property, for instance in the context:
public class MyContext : DbContext
{
public DbSet<Mailout> Mailouts { get; set; }
public IQueryable<Mailout> MailoutsWithStatus
{
get { return Mailouts.Include(m => m.Status); }
}
// ...
}
And then use in your queries:
context.MailoutsWithStatus.Where(...) ... etc.
Only an idea, it's untested.
Taking from Employee Info Starter Kit - upcoming MVC edition, here is a snippet, that works pretty well, to eager load objects when used:
public class Employee
{
...
public int? ReportsTo { get; set; }
[ForeignKey("ReportsTo")]
public virtual Employee Supervisor { get; set; }
/// <summary>
/// Children object collection of foreign key relation
/// </summary>
public virtual List<Employee> Subordinates { get; set; }
}
Related
I am currently facing the following problem:
I have a model class LargeDataClass with many fields (200+).
Many of these fields (~50-80) are enum-like (i.e. they can be filled out with certain sets of options in the UI).
Now my approach was to model these as enum classes, like
[Table("tbl_enum_one")]
class EnumOne {
public int ID { get; set; }
public string Name { get; set; }
}
[Table("tbl_large_dataclass")]
class LargeDataClass {
public EnumOne EnumOne { get; set; }
public int EnumOneId { get; set; }
//...
}
This has the major advantage of being easily extendable (to add a dropdown option in the UI, just add a row to the table).
Now I am facing some concerns/problems:
When I fetch my model class LargeDataClass from the DB with all its enum fields included, there will be a lot of joins (as I stated above, there are like 50 to 80 of these fields). I am worried that will have a big impact on query performance. Plus create/update/delete might be quite slow due to the large number of indexes to be updated.
MySQL won't even let me create a table tbl_large_dataclass with that many FKs (too many indexes on a single table).
So now I am considering two (in my view really unfortunate) options:
Using regular enums, so no enum classes with their own tables, storing them as simple int/string fields in the DB. This would cause no performance concerns at all, but unfortunately, the 'live' extendability is quite important, so this option would only be the last resort.
Using the Enum classes, but having just the ID of the enum in the LargeDataClass, so kind of keeping the fact that this is a foreign key secret from the DB. If I wanted to display a LargeDataClass object somewhere, I would have to separately fetch the enum classes. Plus I would have to make extra sure everywhere that I only use Ids that are really present in the enum table.
I am really unsure what would be the best approach here.
Database is not an object store and you have to design it accordingly. I have changed you schema and only two tables are needed for storing dropdown values.
[Table("tbl_enum_type")]
public class EnumType {
public int ID { get; set; } // PK
public string Name { get; set; }
}
// PK (EnumTypeId, Id) - reusing the same index for dropdown generation
[Table("tbl_enum_value")]
public class EnumValue {
public int ID { get; set; }
public string Name { get; set; }
public int Order { get; set; } // for dropdown ordering
public int EnumTypeId { get; set; }
public EnumType EnumType { get; set; }
}
// store only ID's, no FK
[Table("tbl_large_dataclass")]
public class LargeDataClass {
public int EnumOneId { get; set; } // EnumTypeId 1
public int EnumSecondId { get; set; } // EnumTypeId 2
//...
}
For generating dropdowns, you have to cache EnumType and EnumValue tables in memory in useful structure.
Override method SaveChanges/SaveChangesAsync and check saved Id's according to cached data.
It will not help if your database is changed via SQL, but here we have trade-off between performance and consistency. Probably good trigger may help here.
UPDATE:
Consider to restructure LargeDataClass to two tables
[Table("tbl_option_bag")]
public class OptionBag {
public int Id { get; set; }
public ICollection<Option> Options { get; set; }
}
[Table("tbl_options")]
public class Option {
public int Id { get; set; }
public int OptionBagId {get; set; }
public int EnumTypeId { get; set; }
public int EnumId { get; set; }
//...
}
Here you can use FK and DTO can be generated on selecting Options navigation property.
I've manay-to-many relationship between two entities: Categories <--> Items
public class CategoryMaster
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual List<SubCategoryMaster> SubCategories { get; set; }
public List<ItemMaster> Items { get; set; }
}
public class ItemMaster
{
public long Id { get; set; }
public string Name { get; set; }
public List<CategoryMaster> Categories { get; set; }
}
Whenever I try to explicit load related items to all/certain categories, it gives me
all related items
related categories to those items
related items to those categories and so on...nested/circular references
db.CategoryMaster
.Include(x=>x.Items)
.Include(x=>x.SubCategories.Select(y=>y.Items))
.ToList();
Hence results in below error while serializing it to JSON on *.cshtml with Json.Encode();
A circular reference was detected while serializing an object of type 'GoGreen.Data.Entities.SubCategoryMaster'.
Since I've disabled the lazy loading at property level, I'm not expecting it to load all nested entities(circular references) at any point of time. Is there a way to load all related level one records i.e. Categories and related items.
Related question - But Iodon't want to go with any of the two ways suggested.
NOTE : I'm more interested in knowing why EF behaves like this. It seems a bug to me.
First approach: you can add attribute above properties you don't want to exclude it from being serialized using [ScriptIgnore], you can create partial class and add your customization if your entities are auto generated
Second approach: Create a Model with only properties you need in your view and select only this model and set your properties
EFcontext.Tabel.include(x=>x...).Select(x=>new MyModel { ... });
One workaround, and please don't kill me :-) After object loading and before serializing, just set the loaded objects which are causing the circular reference to null. I tried it and worked like a charm.
use meta data redirection. figured I would help anyone who stumbled here.
[MetadataType(typeof(CategoryMasterMetadata))]
public partial class CategoryMaster
{
}
public class CategoryMasterMetadata
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
public virtual List<SubCategoryMaster> SubCategories { get; set; }
public List<ItemMaster> Items { get; set; }
}
I know there are a couple of options to exclude/include some parameters in a modelview like using bind or using interfaces. However I have some problems when I am trying to implement nested IEnumerable variables. For example:
public class TestViewModel()
{
public int Id { get; set; }
public IEnumerable<Organisation> KPI { get; set; }
}
public class Organisation
{
public string Id { get; set; }
public string Name {get; set;}
public DateTime StartDate {get; set;}
public IEnumerable<Regiod> CategoryValues { get; set; }
}
public class Region
{
public System.Guid Id { get; set; }
public System.Int32 RegionId { get; set; }
public int Value { get; set; }
public System.String RegionName { get; set; }
}
[HttpGet]
public ActionResult edit(int id)
{
var model = new TestViewModel();
// Do something to populate the model
view(model)
}
In the view page (razor) all fields are disabled or hidden, except field Value in Region class and StartDate in Organization. My action Code is something like:
[HttpPost]
public ActionResult edit(TestViewModel model)
{
// Do something to populate the model
}
Everything works fine, unless somebody uses for example fiddler to set other disabled or hidden values, so those fields will be updated.
What I am after is to update just enabled fields and exclude the rest even somebody tries to set a value for them.
I tried bind[Exclude and Include], but my problem is I can bind 2 values from different classes. I tried UpdateModel(model, include) and it didn't work.
Any advice would be appreciated.
When defining a relationship between two types is it important to include a navigation property on both types, such as in the following example:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
Can I do without including the navigation property in Category ?
If you just want it infered by code first convention then yes you need both on either side. I'd also make the collection "virtual" to support lazy loading.
You can set it up using the fluent configuration when the model is built. It would be something like this
modelBuilder.Entity<Product>()
.HasMany(x => x.Category)
My question is similar to this one :
--> Many to one configuration using EF 4.1 code first
There are some fluent API solutions on google, with overriding "OnModelCreating" method and manually setting the foreign key options. But i would prefer a solution with data annotations if it is possible. Because I'd like to use inverse properties while coding. Such as TypeA object has got a TypeB object. So TypeB object should have a ParentTypeA property. Example :
public class User : IUser
{
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[RegularExpression(#"[A-Za-z0-9_\-\.]{2,32}"), MinLength(2), MaxLength(32)]
[Required(AllowEmptyStrings = false)]
public string UserName { get; set; }
// other props ....
// ....
public virtual UserGallery Gallery { get; set; }
}
public class UserGallery : IUserGallery
{
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserGalleryId { get; set; }
// other props ....
// ....
public virtual User ParentUser { get; set; }
}
A conventions way to do this in Code First is to use the UserID as the Primary Key of the UserGallery object. This is fine if its a true one to one relationship.
public class UserGallery : IUserGallery
{
[Key]
public int UserId {get;set;}
public User User {get;set;}
etc...
}
This has worked fine for me in the past.