Required attribute in Buddy Class not working with Entity Framework 5 and ASP.NET - asp.net

My database has a field that is not nullable, but can contain an empty string. When I try to save the record using connection.SaveChanges(), I get an exception saying "The MyField field is required."
I have created a BuddyClass as follows, but I still get the message:
namespace MyNamespace {
[MetadataType(typeof(QuesT_Metadata))] public partial class QuesT { }
public class QuesT_Metadata {
[Required(AllowEmptyStrings = true)
public string MyField { get; set; }
}
}
I can use the ErrorMessage attribute to change the message in the error that is thrown, so I know the Buddy Class is working properly, but apparently the Required attribute is not.
I also tried including attribute DisplayFormat(ConvertEmptyStringToNull = false), but got the same result.
I have done this before, and also the first reference below seems to say it should work, so I'm stumped. Can anyone help?
References (Only the first two seem directly relevant, but the others may still be helpful):
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.requiredattribute.allowemptystrings.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayformatattribute.convertemptystringtonull.aspx
How to make an Entity Framework property NOT NULL, but not required in form submission
Data annotation attributes not working using buddy class metadata in an MVC app
Data validation with custom attributes (AttributeTargets.Class) on EF buddy classes

I'm in the same boat here... I've got several instances of your exact behavior which are working just fine....
and now, one particular field won't behave...
But, if I leave off the "Required(AllowEmptyStrings = true)" attribute, things go back to working just fine. Which, I guess is what I'm really looking for, as the attribute in question doesn't really make all that much sense (Required, but allow the user not to answer).....
For me the bigger question is why it sometimes works, and sometimes doesn't ?
But at a miminum, deleting the one like of code should solve the problem for you.

I have worked around this by trapping the error:
public static class ExtensionMethods {
public static void SaveChangesWithEmptyStrings(this DbContext context) {
try {
context.SaveChanges();
}
catch (DbEntityValidationException ex) {
foreach (DbEntityValidationResult result in ex.EntityValidationErrors)
foreach (DbValidationError error in result.ValidationErrors) {
Type t = result.Entry.Entity.GetType();
PropertyInfo pi = t.GetProperty(error.PropertyName);
pi.SetValue(result.Entry.Entity, "");
}
context.SaveChanges(); // Try again
}
}
}

Related

EF5 code first - You cannot use Ignore method on the property

This question has been asked all over the place, but the SUPPOSED workaround on CodePlex does not work.
I'm hoping someone has some updated information.
I have an EF5 Code First project where I have dozens of entities directly derived from an abstract base class. After creating some new entities that are derived from a class derived from that base class, when my database is initially created I get the following error:
You cannot use Ignore method on the property 'DisplayString' on type
'Doctor' because this type inherits from the type
'Contact' where this property is mapped. To exclude
this property from your model, use NotMappedAttribute or Ignore
method on the base type.
Here's my classes:
public abstract class AbsoluteBaseClass
{
[NotMapped]
public abstract string DisplayString { get; set; }
...
}
public class Contact : AbsoluteBaseClass
{
[NotMapped]
public override string DisplayString
{
get { return string.Format("{0} {1}", FirstName, LastName); }
set { throw new System.NotImplementedException(); }
}
...
}
public class Doctor : Contact
{
...
}
I have other cases like this (class derived from a class derived from the base) and I've got things working, but adding these new classes broke things again.
I've also tried add .Ignore directives (derived class before base) in OnModelCreating and that does not make any difference either.
modelBuilder.Entity<Doctor>().Ignore(p => p.DisplayString);
modelBuilder.Entity<Contact>().Ignore(p => p.DisplayString);
I have several cases where I have entities derived from AbsoluteBaseClass and most times things work, but then I would add another derived class and things would break again. There appears to be no rhyme or reason to this.
I'd REALLY appreciate some advice on how I can definitively get this to work as I add classes. There appears mention around of a fix applied to the EF5 source,then you build the source. Has anyone tried that and got it to work?
Thanks for any advice!
Corey.
In my case, when using Code First (EF6) on an existing database, I created some base classes to handle the common properties like ID.
(Note: the following are inside the OnModelCreating(DbModelBuilder mb) method)
I then needed to ignore the base classes entirely with:
mb.Ignore(new[] {
typeof(BaseClassA),
typeof(BaseClassB)
});
Then, somewhat counterintuitively, I needed to register the base model properties with:
mb.Entity<BaseClassA>().HasKey(m => m.ID);
mb.Entity<BaseClassB>().Whatever...
One of my derived classes needed to ignore one of the base properties (call it NormallyNotIgnored). I used EntityTypeConfiguration, but I assume you could do the same with regular Fluent:
mb.Entity<DerivedClassB1>().Ignore(m => m.NormallyNotIgnored);
This at least has compiled/migrated (with -IgnoreChanges on the migration, since the tables already exist) and resolved the error in question.

BreezeJs Fails to Load Metadata for EF Code First Schema with Inherited Class

Just started trying out Breeze today, long time EF user - think I found a bug in Breeze, but I may be doing something wrong - want to know which it is:
I have a simple hierarchy in EF Code First:
// For testimonials about the product line in general
public class Testimonial
{
public int Id { get; set; }
public string Text { get; set; }
}
// For testimonials specific to a single product
[Table("ProductTestimonial")]
public class ProductTestimonial : Testimonial
{
public Product Product { get; set; }
}
So just to be clear there's 2 tables here, Testimonial and ProductTestimonial, both have a PK of Id, and a Text field, and one of them also has an FK off to Product. This is just a simple way of implementing Table Per Type.
So I setup the BreezeController via WebApi:
[BreezeController]
public class EFController : ApiController
{
private readonly EFContextProvider<EfDb> _db = new EFContextProvider<EfDb>();
[HttpGet]
public string Metadata()
{
return _db.Metadata();
}
And I go to load it in breeze.js:
var manager = new breeze.EntityManager('/api/ef');
manager.executeQuery(breeze.EntityQuery.from('Product');
Kablamo. Exception. It says:
Unable to get value of the property 'propertyRef': object is null or undefined
At:
function convertFromODataEntityType(... {
. . .
var keyNamesOnServer = toArray(odataEntityType.key.propertyRef)...
Where odataEntityType.name == 'ProductTestimonial', and .key sure enough is undefined.
Which is true. Picking things apart, when I call executeQuery(), Breeze hits the Metadata call on the WebApi, which I verified calls and returns successfully. The massive JSON string returned from there includes:
{
"name": "ProductTestimonial",
"baseType": "Self.Testimonial",
"navigationProperty": {
"name": "Product",
"relationship": "Self.ProductTestimonial_Product",
"fromRole": "ProductTestimonial_Product_Source",
"toRole": "ProductTestimonial_Product_Target"
}
},
{
"name": "Testimonial",
"key": {
"propertyRef": {
"name": "Id"
}
},
So it would appear the basic issue is that the Metadata is accurately portraying ProductTestimonial as an inherited class, whose key is defined elsewhere, but Breeze.js - if I'm understanding it correctly - is naively just checking the .key property without considering superclasses. But, I could be wrong since I'm so new to Breeze.
Addendum:
I don't think it's relevant here but in case it comes up, yes I do have an IQueryable as well on the WebApi Controller:
[HttpGet]
public IQueryable<Product> Products()
{
return _db.Context.Products;
}
Also, I recognize a potential workaround here is probably to discard TPT and make full classes for every Entity with no inheritance, but I'm really slimming my example down here - there's a lot of inheritance throughout the EF model that has to stay. If it's inheritance or Breeze, Breeze is getting the axe.
Edit: As of v 1.3.1 Breeze now DOES support inheritance.
Inheritance is coming but we don't have a fixed date just yet. Please vote for the feature on the Breeze User Voice. We take these suggestions very seriously.
I don't think manager.fetchEntityByKey works with inheritance - can any of the Breeze guys confirm whether this is correct? It seems to be picking up the inherited fields from my base class, but not the fields from my derived class. I can get the full object by using entityQuery but then I have to name every field. When I do that I'm still getting parse errors on ko bindings.

Why isn't server side validation working in my ASP.Net MVC3 application with Entity Framework?

I have an ASP.NET MVC3 application that uses entities generated from a database. Each entity has also has a separate partial class that uses the MetadataType attribute to associate each entity with a class that is decorated with a number of validation attributes (see below).
[MetadataType(typeof(Drawing.Metadata))]
public partial class Drawing
{
private sealed class Metadata
{
[Required]
[StringLength(50, MinimumLength = 3, ErrorMessage = "Drawing numbers must be between {2} and {1} characters in length.")]
[DisplayName("Drawing number")]
public string Number { get; set; }
[Required]
[StringLength(255, MinimumLength = 3, ErrorMessage = "Drawing titles must be between {2} and {1} characters in length.")]
public string Title { get; set; }
}
}
My controller code looks like this:
[HttpPost]
public ActionResult Create(Drawing drawing)
{
if (ModelState.IsValid)
{
// Save to database here...
return RedirectToAction("Index");
}
else
{
return View(drawing);
}
}
I have used the Visual Studio templates to create the views to add, edit and delete the entities (The designer code has not been altered).
The problem I am having is that when I create an entity, validation only works if I have client side validation enabled. If I turn off the client side validation then ModelState.IsValid always seems to return true and returns me to the index page.
Can anyone provide any suggestions on how to get server side validation working with Entity Framework entities?
UPDATE:
It seems this question is similar to mine. The author of this post seems to have solved the problem but rather unhelpfully omitted to mention how they fixed the problem...
I found another solution to this problem. Because I didn't really want to set my properties to nullable I added the following:
[DisplayFormat(ConvertEmptyStringToNull = false)]
Adding the following annotation to your model property fixes the error as well.
After further investigation it seems that my problem is occuring due to a ConstraintException being thrown by my entity class (which inherits from ObjectContext) when the default model binder tries to bind the user input values (Null in this case) to the entity properties.
I can see 2 possible solutions to this:
Relax the constraints on my database tables (I don't want to do this).
Make the entity fields nullable (use the entity designer set the nullable property to yes)
I have used and tested the second option and can confirm that server side validation now works as expected.
Whilst researching solutions to this problem I have come to the conclusion that the problem is due to my entities inheriting from ObjectContext which is quite a heavy class. I found a lot of tutorials which used a code-first approach. In this case, the entity class will inherit from DbContext which is much more lightweight so I guess this could be considered a third solution to the problem.

Entity Framework and MVC 3: The relationship could not be changed because one or more of the foreign-key properties is non-nullable

I have been trying to use one View for updating an object and all its child collections (based on one-to-many relationships in an SQL Server database with an Entity Framework model).
It was suggested I should use AutoMapper, and I tried that and got it to work. (see Trying to use AutoMapper for model with child collections, getting null error in Asp.Net MVC 3 ).
But the solution is really hard to maintain. And when I try the simple one I had to begin with, using an entity object directly as the model (a "Consultant" object, the parent of all the child collections), I am able to get all the correct changed data back in the POST, and I can use UpdateModel to get them, including child collections. Simple. Granted, UpdateModel only worked after creating a custom model binder from a tip here at SO:
From my custom model binder:
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
return base.BindModel(controllerContext, bindingContext);
}
protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
{
ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name];
propertyMetadata.Model = value;
string modelStateKey = CreateSubPropertyName(bindingContext.ModelName, propertyMetadata.PropertyName);
// Try to set a value into the property unless we know it will fail (read-only
// properties and null values with non-nullable types)
if (!propertyDescriptor.IsReadOnly)
{
try
{
if (value == null)
{
propertyDescriptor.SetValue(bindingContext.Model, value);
}
else
{
Type valueType = value.GetType();
if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(EntityCollection<>))
{
IListSource ls = (IListSource)propertyDescriptor.GetValue(bindingContext.Model);
IList list = ls.GetList();
foreach (var item in (IEnumerable)value)
{
list.Add(item);
}
}
else
{
propertyDescriptor.SetValue(bindingContext.Model, value);
}
}
}
catch (Exception ex)
{
// Only add if we're not already invalid
if (bindingContext.ModelState.IsValidField(modelStateKey))
{
bindingContext.ModelState.AddModelError(modelStateKey, ex);
}
}
}
}
Here's my simple Edit POST method:
[HttpPost]
[ValidateInput(false)] //To allow HTML in description box
public ActionResult Edit(int id, FormCollection collection)
{
Consultant consultant = _repository.GetConsultant(id);
UpdateModel(consultant);
_repository.Save();
return RedirectToAction("Index");
}
But after that UpdateModel worked. The problem is, at the next stage, when trying to call SaveChanges on the context, that fails. I'm getting this error:
The operation failed: The relationship
could not be changed because one or
more of the foreign-key properties is
non-nullable. When a change is made to
a relationship, the related
foreign-key property is set to a null
value. If the foreign-key does not
support null values, a new
relationship must be defined, the
foreign-key property must be assigned
another non-null value, or the
unrelated object must be deleted.
I don't understand what is wrong. I'm seeing all the correct values in the Consultant object posted, I just can't save it to database. The route of AutoMapper in this case (although an interesting tool) is not working well, it's complicating my code immensely and making the application, which should be rather simple, a nightmare to maintain.
Can anyone offer any insight into why I'm getting this error and how to overcome it?
UPDATE:
Reading some posts here, I found one that seemed slightly related: How to update model in the database, from asp.net MVC2, using Entity Framework? . I don't know if it relates to this, but when I inspected the Consultant object after POST it seems this object itself has entitykey, but the individual items in a collection do not (EntityKeySet = null). Each item however does have the correct id. I don't pretend to understand any of this with the EntityKey, so please explain if it has any bearings on my issue, and if so, how to resolve it...
UPDATE 2:
I thought of something that might have something to do with my problems: The View is using a technique described by Steven Sanderson (see http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/ ), and when debugging it seems to me as if UpdateModel has trouble matching the items in a collection in the View with the ones in the actual Consultant object. I'm wondering if this has to do with the indexing in this technique. Here's the helper from that code (I can't follow it very well myself, but it uses a Guid to create indexes, which might be the problem):
public static class HtmlPrefixScopeExtensions
{
private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";
public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
{
var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();
// autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));
return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
}
public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
{
return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
}
private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
{
// We need to use the same sequence of IDs following a server-side validation failure,
// otherwise the framework won't render the validation error messages next to each item.
string key = idsToReuseKey + collectionName;
var queue = (Queue<string>)httpContext.Items[key];
if (queue == null)
{
httpContext.Items[key] = queue = new Queue<string>();
var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
if (!string.IsNullOrEmpty(previouslyUsedIds))
foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
queue.Enqueue(previouslyUsedId);
}
return queue;
}
private class HtmlFieldPrefixScope : IDisposable
{
private readonly TemplateInfo templateInfo;
private readonly string previousHtmlFieldPrefix;
public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
{
this.templateInfo = templateInfo;
previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
}
public void Dispose()
{
templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
}
}
}
But then again, I wouldn't have thought this should be the problem since the hidden input contains the id in the value attribute, and I thought UpdateModel just looked at the name of the field to get Programs (the collection) and Name (the property), and then the value to the the id...? And then again there's seems to be some mismatch during update. Anyway, here's the generated html from FireBug also:
<td>
<input type="hidden" value="1" name="Programs[cabac7d3-855f-45d8-81b8-c31fcaa8bd3d].Id" id="Programs_cabac7d3-855f-45d8-81b8-c31fcaa8bd3d__Id" data-val-required="The Id field is required." data-val-number="The field Id must be a number." data-val="true">
<input type="text" value="Visual Studio" name="Programs[cabac7d3-855f-45d8-81b8-c31fcaa8bd3d].Name" id="Programs_cabac7d3-855f-45d8-81b8-c31fcaa8bd3d__Name">
<span data-valmsg-replace="true" data-valmsg-for="Programs[cabac7d3-855f-45d8-81b8-c31fcaa8bd3d].Name" class="field-validation-valid"></span>
</td>
Anyone know if this is the problem? And if so, how can I work around it to be able to easily update the collections with UpdateModel? (While still being able to add or remove items in the View before POST, which was the purpose of this technique to begin with).
It looks like there is a Parent entity that has a one to many relationship with your Consultant entity. When you change an attribute of the Consultant entity that is used as the ForeignKey for that relationship, Entity Framework sets the relevant field in the Parent entity to null to decouple the relationship. When that field is not nullable you'll get this error. Actually that error definition is surprisingly good, I've seen this problem with far more cryptic errors.
So, I recommend that you check the parent entity in the database, and proceed to a remedy from there (if you can change it to nullable all is well, if it is part of a different constraint -pk or suchlike- you'll have to fiddle with your object models). I'd ask you to post your entity models, but the chunk of text is intimidating as it is.
I think the error you are getting is related to: EF 4: Removing child object from collection does not delete it - why? You have created an orphan somewhere.
Yes it is related to HtmlPrefixScopeExtensions, but only because you are using Mvc Futures model binders.
In global.asax.cs comment out the line
Microsoft.Web.Mvc.ModelBinding.ModelBinderConfig.Initialize();
and retry: it will work ok !
The problem happens because the MVC futures model binder does not handle correctly this case. It converts ok the form data into your model when you submit the form, but it has a problem when filling the ModelState object when you use HtmlPrefixScopeExtensions to generate non incremental ids.
The model itself is correctly created from the form data. The problem lies inside ModelState which contains only the last value of the collection instead of all elements of the collection.
The strongly typed helper method - which renders the list - only select items which are in your Model property list AND in the matching ModelState entry which is converted into a list. So because there is only one item in the matching ModelState entry other list items get deselected.
This method called by the strongly typed helper code:
htmlHelper.GetModelStateValue(fullName, typeof(string[]))
returns only the last element of the list, because ModelState["Programs[cabac7d3-855f-45d8-81b8-c31fcaa8bd3d].List"].Value contains only the last element of the list.
This is a bug (or non supported scenario) in MVC3 Futures extensible model binders.

linq-to-sql "an attempt has been made to attach or add an entity that is not new"?

I've been getting several errors:
cannot add an entity with a key that is already in use
An attempt has been made to attach or add an entity that is not new, perhaps having been loaded from another datacontext
In case 1, this stems from trying to set the key for an entity versus the entity. In case 2, I'm not attaching an entity but I am doing this:
MyParent.Child = EntityFromOtherDataContext;
I've been using using the pattern of wrap everything with a using datacontext. In my case, I am using this in a web forms scenario, and obviously moving the datacontext object to a class wide member variables solves this.
My questions are thus 2 fold:
How can I get rid of these errors and not have to structure my program in an odd way or pass the datacontext around while keeping the local-wrap pattern? I assume I could make another hit to the database but that seems very inefficient.
Would most people recommend that moving the datacontext to the class wide scope is desirable for web pages?
Linq to SQL is not adapted to disconnected scenarios. You can copy your entity to a DTO having a similar structure as the entity and then pass it around. Then copy the properties back to an entity when it's time to attach it to a new data context. You can also deserialize/reserialize the entity before attaching to a new data context to have a clean state. The first workaround clearly violates the DRY principle whereas the second is just ugly. If you don't want to use any of these solution the only option left is to retrieve the entity you're about to modify by its PK by hitting the DB. That means an extra query before every update. Or use another ORM if that's an option for you. Entity Framework 4 (included with .NET 4) with self-tracking entities is what I'm using currently on a web forms project and everything is great so far.
DataContext is not thread-safe and should only be used with using at the method level, as you already do. You can consider adding a lock to a static data context but that means no concurrent access to the database. Plus you'll get entities accumulated in memory inside the context that will turn into potential problems.
For those that came after me, I'll provide my own take:
The error "an attempt has been made to add or attach an entity that is not new" stems from this operation:
Child.Parent = ParentEntityFromOtherDataContext
We can reload the object using the current datacontext to avoid the problem in this way:
Child.Parent = dc.Entries.Select(t => t).Where(t => t.ID == parentEntry.ID).SingleOrDefault();
Or one could do this
MySubroutine(DataContext previousDataContext)
{
work...
}
Or in a web forms scenario, I am leaning to making the DataContext a class member such as this:
DataContext _dc = new DataContext();
Yes, the datacontext is suppose to represent a unit of work. But, it is a light-weight object and in a web forms scenario where a page is fairly transient, the pattern can be changed from the (using dc = new dc()) to simply using the member variable _dc. I am leaning to this last solution because it will hit the database less and require less code.
But, are there gotchas to even this solution? I'm thinking along the lines of some stale data being cached.
What I usually do is this
public abstract class BaseRepository : IDisposable
{
public BaseRepository():
this(new MyDataContext( ConfigurationManager.ConnectionStrings["myConnection"].ConnectionString))
{
}
public BaseRepository(MyDataContext dataContext)
{
this.DataContext = dataContext;
}
public MyDataContext DataContext {get; set;}
public void Dispose()
{
this.DataContext.Dispose();
}
}
Then imagine I have the following repository
public class EmployeeRepository : BaseRepository
{
public EmployeeRepository():base()
{
}
public EmployeeRepository(MyDataContext dataContext):base(dataContext)
{
}
public Employee SelectById(Guid id)
{
return this.DataContext.Employees.FirstOrDefault(e=>e.Id==id);
}
public void Update(Employee employee)
{
Employee original = this.Select(employee.Id);
if(original!=null)
{
original.Name = employee.Name;
//others
this.DataContext.SubmitChanges();
}
}
}
And in my controllers (I am using asp.net mvc)
public ActionResult Update(Employee employee)
{
using(EmployeeRepository employeeRepository = new EmployeeRepository())
{
if(ModelState.IsValid)
{
employeeRepository.Update(employee);
}
}
//other treatment
}
So the datacontext is properly disposed and I can use it across the same instance of my employee repository
Now imagine that for a specific action I want the employee's company to be loaded (in order to be displyed in my view later), I can do this:
public ActionResult Select(Guid id)
{
using(EmployeeRepository employeeRepository = new EmployeeRepository())
{
//Specifying special load options for this specific action:
DataLoadOptions options = new DataLaodOptions();
options.LoadWith<Employee>(e=>e.Company);
employeeRepository.DataContext.LoadOptions = options;
return View(employeeRepository.SelectById(id));
}
}

Resources