EF Code First: model type is not pluralized in the repository - asp.net-mvc

I have a State model class:
public class State
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
}
And I am trying to create a Repository:
Scaffold Repository State
I've got in generated file:
public IQueryable<State> All
{
get { return context.State; }
}
instead of context.StateS.
Property
public DbSet<State> States { get; set; }
successfully has been added to the DbContext class.
I have no overrided OnModelCreating method.
Sometimes I mention such problem in different projects but can not find a reason.

I know I've had problems with namespace confusion when using the word "State" for my database tables and POCOs. So to make things easier, I rename those to something else, like USState or StateCode. That could be what's going on here for you and the scaffolding.

Related

ASP.NET MVC 3 EF Code First - How do I make a model that optionally refers to a parent of its own type?

I'm trying to create a model that can optionally refer to a parent of the same type, for example:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category? ParentCategory { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
As you can see there is an optional member called ParentCategory that is optional and refers to a class of type Category (i.e. the same type). As I'm sure you can guess, I'm trying to create a simple Category tree, where the root node(s) will not have a parent.
This results in the following error when the Entity Framework tries to create the database:
"The ForeignKeyAttribute on property 'ParentCategoryID' on type 'MyProject.Models.Category' is not valid. The navigation property 'Category' was not found on the dependent type 'MyProject.Models.Category'. The Name value should be a valid navigation property name."
I also tried this:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("Category")]
public virtual long? ParentCategoryID { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
But again this resulted in the same error.
Is it possible to model this using EF Code First? Its easy to model it int he database if I were to create the database manually.
Thanks in advance
Ben
Your first example wouldn't even compile because T?, a shortcut for Nullable<T> can only be applied to value types.
The following works fine here:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category ParentCategory { get; set; }
}
Now, this will use an ugly name by default for the FK, ParentCategory_CategoryID.
This is a way to get a nicer name, plus some flexibility when using it:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("ParentCategoryID")]
public virtual Category ParentCategory { get; set; }
public virtual long? ParentCategoryID { get; set; }
}

MvcScaffolding Keeps Pluralize DbSet item name

here is my model classes;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ContactFormWithMultipleCheckboxApp.Models {
public class Product {
public int ProductId { get; set; }
[Required, StringLength(50)]
public string ProductName { get; set; }
public string Description { get; set; }
public virtual ICollection<Message> Messages { get; set; }
}
public class Message {
public int MessageId { get; set; }
public string From { get; set; }
[Required]
//below one is to validate whether the e-mail address is legit or not
[RegularExpression("\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}\b")]
public string Email { get; set; }
[StringLength(100)]
public string Subject { get; set; }
public string Content { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
}
And I have installed MvcScaffolding as nuget package to my app. I am trying to a simple scaffolding with following code;
PM> Scaffold Controller Message
it works and creates my controllers, views and DBContect class. but I have one problem. why does it pluralize my dbset item inside dbcontect class;
public class ContactFormWithMultipleCheckboxAppContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, add the following
// code to the Application_Start method in your Global.asax file.
// Note: this will destroy and re-create your database with every model change.
//
// System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<ContactFormWithMultipleCheckboxApp.Models.ContactFormWithMultipleCheckboxAppContext>());
public DbSet<ContactFormWithMultipleCheckboxApp.Models.Message> Messages { get; set; }
}
as you can see it creates the name as Messages but it uses Message on the other places like view and controller.
What is happening here?
In this blog post about MvcScaffolding 0.9.4, Steve Sanderson writes:
"Based on your feedback, controller
names are now pluralized by default
(e.g., you get PeopleController rather
than PersonController for a model of
type Person, unless you explicitly
enter PersonController as the
controller name when scaffolding)"
So by default (or convention) it pluralizes your names unless you tell it not to. You stated that you did that, and it didn't pluralize your controller or views.
I wonder if you also need to tell EntityFramework not to pluralize. See this post, "How to singularize in EntityFramework" for more details about that.

EF4 CTP5 - Map foreign key without object references?

I feel like this should have a simple answer, but I can't find it.
I have 2 POCOs:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Product
{
public int Id { get; set; }
public int CategoryId { get; set; }
}
Notice that there are no object references on either POCO. With Code-First, how do I make EF4 CTP5 define a relationship between the two database tables?
(I know this is an unusual scenario, but I am exploring what's possible and what's not with Code-First)
No, this is not possible. As you can see below, all of the fluent API methods for setting up associations require specifying the Navigation Property as their parameter.
HasMany<TTargetEntity>(Expression<Func<TEntityType, ICollection<TTargetEntity>>> navigationPropertyExpression)
HasOptional<TTargetEntity>(Expression<Func<TEntityType, TTargetEntity>> navigationPropertyExpression)
HasRequired<TTargetEntity>(Expression<Func<TEntityType, TTargetEntity>> navigationPropertyExpression)
Is there any particular reason you don't want to use object references? It looks very elegant to use them:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public Category Category { get; set; }
}
And you can still access the Category Id via your product as product.Category.Id.

EF CTP4: How to tell EF a column is NOT identity

I have a code-first, POCO project in which I am trying to adjust an existing database so that it syncs up with what EF is expecting, given my existing model.
I have these entities:
public class FlaggedDate
{
[Key]
public long scheduledDayID { get; set; }
[Required]
public DateTime date { get; set; }
[StringLength(50)]
[Required]
public string dateStatus { get; set; }
[Required]
public bool isVisit { get; set; }
[Required]
public bool hasAvailableSlots { get; set; }
[Required]
public bool hasInterviewsScheduled { get; set; }
// navigation properties
public ICollection<ScheduledSchool> scheduledSchool { get; set; }
public ICollection<Interview> interviews { get; set; }
public ICollection<PartialDayAvailableBlock> partialDayAvailableBlocks { get; set; }
public Visit visit { get; set; }
public ICollection<Event> events { get; set; }
}
and
public class Visit
{
[Key]
public long flaggedDateScheduledDayID { get; set; }
[Required]
public bool isFullDay { get; set; }
// navigation property
public FlaggedDate flaggedDate { get; set; }
}
The relationship between these two is 1 : 0|1 -- i.e., FlaggedDate will exist but it may or may not have a corresponding single Visit object.
EF thinks, based on this model, that FlaggedDate should have an extra field, visit_flaggedDateScheduledDayID, which is nullable. I finally realized why: it thinks the Visit field, flaggedDateScheduledDayID, is an identity column. It's not supposed to be an identity column; it's supposed to be a foreign key that connects to FlaggedDate.
I think it does this by convention: I remember reading something to the effect that in CTP4, any field that is a single key and is int or long is assumed to be an identity column.
Is there any way I can tell EF that this is NOT an identity column? I tried fiddling with the Fluent API, but it's a mystery to me, and there are no data annotations that you can use for this.
Or, alternatively, is there any way I can fiddle with the navigation properties to get this to come out right?
If you're using mapping files with fluent API
this.Property(t => t.Id)
.HasColumnName("Site_ID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
I would imagine it should also work declaratively
[HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)]
although I didn't try that.
I discovered I can override the identity behavior with this code:
modelBuilder.Entity<Visit>().Property(v => v.flaggedDateScheduledDayID).StoreGeneratedPattern = System.Data.Metadata.Edm.StoreGeneratedPattern.None;
However, it is still not making it a foreign key. I guess that's a different question, though. It seems setting the StoreGeneratedPattern to None is the way to override the default behavior.

ASP.NET-MVC2: Why does TryUpdateModel ignore properties after the second level of the object model tree?

Perhaps I'm missing something here, but it seems that anything in the object model tree 3 or more levels down, is ignored when using TryUpdateModel.
For example (simplified):
public virtual ActionResult SomeAction(int id, FormCollection form)
{
IValueProvider vpFrom = form.ToValueProvider();
/*
At this stage, vpForm contains:
1)PropertyA
2) PropertyB.SubPropertyA
3) PropertyB.SubPropertyB.SubSubPropertyA
*/
TryUpdateModel(someObjectModel, null, null, null, vpFrom);
//The first two properties are applied, number (3) seems to be ignored
Am I missing something here? If this is just the way it is, has anyone come up with a workaround?
A quick project created with the following model.
public class TestModel {
public TestModelA A { get; set; }
public string Name { get; set; }
}
public class TestModelA {
public TestModelB B { get; set; }
public string Name { get; set; }
}
public class TestModelB {
public TestModelC C { get; set; }
public string Name { get; set; }
}
public class TestModelC {
public TestModelD D { get; set; }
public string Name { get; set; }
}
public class TestModelD {
public TestModelE E { get; set; }
public string Name { get; set; }
}
public class TestModelE {
public string Name { get; set; }
}
Here's my edit - which is essentially the same as yours
[HttpPost]
public ActionResult Edit(FormCollection form) {
IValueProvider vpFrom = form.ToValueProvider();
Models.TestModel t = new Models.TestModel();
TryUpdateModel(t, null, null, null, vpFrom);
return View(t);
}
This all works exactly as expected with all the models created properly. The only problem that I can see happening is that you possibly aren't passing the same property names back from the form. (by not using <%: Html.TextBoxFor(model => model.A.B.C.CName)%> for example)
The models require parameterless constructors. But I'm sure you would have gotten an error about that - unless you're consuming the error.
So without more information about your project it will be hard to help as a basic setup produces expected results.
I believe the problem is in one of your model classes. Check, please, if PropertyB.SubPropertyB.SubSubPropertyA is really a property but not a field. A property should have get and set accessors.
Here's my checklist:
Make sure you're getting the value back in the form request. Request["A.B.C.Name"] and etc.
All the required fields are on the form.
I had deleteOnNull issue with Linq to SQL: How to set DeleteOnNull from designer for future ref if you're using L2SQL.

Resources