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.
Related
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; }
}
I'm trying to add an object to an IList entity but the runtime throws a 'Object reference not set to an instance of an object.' exception.
Here is my model:
public class Discussion
{
[Key]
public int DiscussionId { get; set; }
public string Title { get; set; }
public virtual List<Message> Messages { get; set; }
public virtual List<Tag> Tags { get; set; }
public Guid Guid { get; set; }
public string UrlTitle { get; set; }
}
and here is the problematic line:
newDiscussion.Messages.Add(newMessage);
Apparently newDiscussion.Messages is null. What am I doing wrong?
Mark
You should initialize any collections inside of the class's constructor.
public class Discussion
{
public Discussion()
{
Messages = new List<Message>();
Tags = new List<Tag>();
}
// ...
}
This is my class:
public partial class Event
{
public Event()
{
this.Comments = new HashSet<Comment>();
this.Rates = new HashSet<Rate>();
this.RawDates = new HashSet<RawDate>();
}
public int ID { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string SiteURL { get; set; }
public string ContactEmail { get; set; }
public string LogoURL { get; set; }
public int EventType_ID { get; set; }
public Nullable<int> Location_ID { get; set; }
public Nullable<System.DateTime> BegginingDate { get; set; }
public string nTrain { get; set; }
public string Content { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual Conference Conference { get; set; }
public virtual ICollection<Rate> Rates { get; set; }
public virtual ICollection<RawDate> RawDates { get; set; }
public virtual EventType EventType { get; set; }
public virtual Location Location { get; set; }
}
When I call web api post method, exception mentioned in the title is thrown in this line:
var response = await client.PostAsJsonAsync("api/event", event);
I added [JsonIgnore] above every virtual field in Event class. This time serialization worked, but ignored fields were not serialized, their value is null. I really need all information contained in Event object. How can I solve this problem?
Adding below configuration in WebAPIConfig.cs resolves the bug.
var json = config.Formatters.JsonFormatter;
//Below configuration to mandatory to resolve the Self referencing loop detected with
"Newtonsoft.Json.JsonSerializationException" ,
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
Circular referencing objects cannot be JSON serialized. I would recommend you using a view model in which you will include the properties you need and then have your action return this view model instead of the actual domain model.
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.
I have a class department inheriting from activeentity
public class ActiveEntity : Entity, IActive
{
public ActiveEntity()
{
IsActive = true;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public bool IsActive { get; set; }
[Timestamp, ScaffoldColumn(false), DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Computed)]
public Byte[] Timestamp { get; set; }
[ScaffoldColumn(false)]
public string CreationUserId { get; set; }
[ScaffoldColumn(false)]
public string LastModifiedUserId { get; set; }
}
public class Department:ActiveEntity
{
public Department()
{
this.Address = new DepartmentAddress();
}
[StringLength(9),MinLength(9),MaxLength(9)]
public string Name { get; set; }
public Guid ManagerId { get; set; }
[UIHint("AjaxDropdown")]
public User Manager { get; set; }
public Guid? AddressId { get; set; }
public DepartmentAddress Address { get; set; }
public ICollection<OverheadRate> OverheadRates { get; set; }
}
I am just using annotations no Fluent API. The data saves to the data Sql Server 2008 just fine however the address object never gets instantiated, even though I have the context use the include
return c.Set<Department>().Include(d => d.Address).Include(d => d.Manager).Where(predicate);
The data is returned I run sql profiler and then run the query it returns the correct data.
Any thoughts or suggestions?
Remove instantiating the address (this.Address = new DepartmentAddress();) in the Department constructor. Instantiating navigation references in the default constructor is evil and has nasty side effects like these:
What would cause the Entity Framework to save an unloaded (but lazy loadable) reference over existing data?
EF 4.1 Code First: Why is EF not setting this navigation property?