EF Code First Custom Collections - entity-framework-4.1

When creating code first collections can you implement a custom class that implements ICollection. The code below is conceptual not actual
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; }
//Want to Avoid This
public ICollection<Product> Products { get; set; }
//Use his instead of above
public ProductList ProductsInCategory {get;set;}
}
public class ProductsList :ICollection<Product>
{
public int DiscontinuedProductsCount
{
return internalList.Count();
}
//Icollection Methods Excluded
}

EF can indeed support any collection which inherits from ICollection. We create a deletable collection to support auto deletions and also create collections for child objects to keep the size of our main object smaller.

Related

Populate DropDown from database in an edit view using MVC4

I am new to MVC and trying to populate a dropdown list in the "create" view which is generated from a view model, but it returns with an error saying object reference is not an instance of an object. below is my code :
Controller Code:
public ActionResult Create()
{
return View(new AddRecipeViewModel());
}
Model Code:
public class DifficultyLevel
{
[Key]
public int Id { get; set; }
public string Difficulty { get; set; }
}
public class AddRecipeViewModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<RecipeReview> Reviews { get; set; }
public virtual IEnumerable<DifficultyLevel> Difficulty { get; set; }
}
View:
<div>
<select>
#foreach (var item in Model.Difficulty)
{
<option>#item.Difficulty</option>
}
</select>
</div>
Is there an easy workaround this ? as I will be adding more drop downs in this as I go along.
Thanks,
Vishal
not sure if you need to use virtual in your view models.. that's usually only for the entity models. but anyway, try adding a constructor to AddRecipeViewModel and set the collections equal to empty lists so they won't be null.
public class AddRecipeViewModel
{
public AddRecipeViewModel()
{
Reviews = new List<RecipeReview>();
Difficulty = new List<DifficultyLevel>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<RecipeReview> Reviews { get; set; }
public virtual IEnumerable<DifficultyLevel> Difficulty { get; set; }
}

How to make ICollection<Child Entities> Required. How

Here is my Master Entity who will contains a list of Language
public partial class WebSite
{
public WebSite()
{
this.WebSiteLanguages = new HashSet<WebSiteLanguage>();
}
public int Id { get; set; }
public Nullable<int> WLUserID { get; set; }
public string DomainName { get; set; }
public Nullable<bool> IsActive { get; set; }
//[Required]
public virtual ICollection<WebSiteLanguage> WebSiteLanguages { get; set; }
}
My WebSiteLanguage Child class is
public partial class WebSiteLanguage
{
public int Id { get; set; }
public string LanguageName { get; set; }
public Nullable<int> WebSiteID { get; set; }
public bool IsDefault { get; set; }
public virtual WebSite WebSite { get; set; }
}
In my View, I can Add many language as I want within an ajax call.
My Question is :
Is it possible to make the
public virtual ICollection WebSiteLanguages { get;
set; }
Required. The Website Entity is not valid if there is no WebSiteLanguage created.
Thanks a lot.
As per post http://blogs.msdn.com/b/adonet/archive/2011/05/27/ef-4-1-validation.aspx navigation properties are excluded from facet validation "as you could set the associated FK value and the navigation property would be set on SaveChanges()". To validate that a navigation property is not null you can:
create a custom attribute that validates it (be it on the type or on the property)
implement IValidatableObject interface that does the above
override DbContext.ValidateEntity protected method so that it validates that the property is not null and if this is the case calls base.ValidateEntity() to validate other properties (see this for more details: http://blogs.msdn.com/b/adonet/archive/2010/12/15/ef-feature-ctp5-validation.aspx)
The 3rd solution seems to be the cleanest.

Relationship Using Code first with Existing database

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)

Mapping complex tree object using fluent mappings in EF 4.1?

I need some assistance with how to properly mapping this structure in EF 4.1:
public class Menu: Entity
{
public string Title { get; set; }
public virtual ICollection<MenuItem> MenuItems { get; set; }
}
public class MenuItem: Entity
{
public string Icon { get; set; }
public string Text { get; set; }
public string Action { get; set; }
public string Controller { get; set; }
public string Parameters { get; set; }
public virtual MenuItemType Type { get; set; }
public virtual Guid? ContextMenuId { get; set; }
public virtual Menu ContextMenu { get; set; }
public virtual Guid? ParentMenuItemId { get; set; }
public virtual MenuItem ParentMenuItem { get; set; }
public virtual ICollection<MenuItem> ChildMenuItems { get; set; }
}
The Entity base class has the ID for the enitties and I also have a base mapping class that builds the mappings for the key. Here is what I have so far for the MenuItem class:
public class MenuItemMapping : EntityConfiguration<MenuItem>
{
public MenuItemMapping()
{
HasOptional(mi => mi.ParentMenuItem).WithMany(p => p.ChildMenuItems).HasForeignKey(mi => mi.ParentMenuItemId).WillCascadeOnDelete(false);
HasOptional(mi => mi.ContextMenu).WithMany().HasForeignKey(mi => mi.ContextMenuId).WillCascadeOnDelete(false);
}
}
My concern is in the ContextMenu because it is a Menu type and not sure the best way to handle this type o mapping.
Update
Well, I added an additional mapping for the Menu (in a MenuMapping class similar to the above mapping class) for the collection of Menuitems and it seems to be OK, but I'd still like to know if what I am doing is correct.
Apparently, my mappings were fine. I thought I would have issues with circular references.

Configuring EF code first without a foreign key

I have the following model:
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Catalog> Matches { get; set; }
}
public class Catalog
{
public long Id { get; set; }
public string Title { get; set; }
}
Using Entity Framework code first I configure this using:
public DbSet<Product> Products { get; set; }
public DbSet<Catalog> Catalogs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// not rules setup yet
}
Currently when EF creates my database it creates a nullable foreign key in the Catalogs table called Product_Id. Is there a way to configure EF to not create any foreign key in the Catalog table?
The catalog table contains imported items from a catalog that should have no relation to the Products table. At run time a search query will be fired for each product and the result will be added to the catalog collection of the product object.
For your purpose I would exclude the Matches collection from the model, either by data annotation...
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
[NotMapped]
public virtual ICollection<Catalog> Matches { get; set; }
}
...or in Fluent code:
modelBuilder.Entity<Product>()
.Ignore(p => p.Matches);