Reputation: 47
I am working on PC configurator application and I have a problem with validating. Point of app is to check if socket on motherboard is the same as socket of CPU etc.
I made code first database using scaffolding in Visual Studio 2013.
public class Configuration : IValidatableObject
{
[Key]
public int ConfigurationID { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
[DisplayName("Configuration name")]
public string ConfigName { get; set; }
[ForeignKey("mb_id")]
public MotherBoard MotherBoard { get; set; }
[Column("mb_id", TypeName = "int")]
public Nullable<int> mb_id { get; set; }
[ForeignKey("cpu_id")]
public CPU CPU { get; set; }
[Column("cpu_id", TypeName = "int")]
public Nullable<int> cpu_id { get; set; }
}
This is part of configuration model that I am using (rest of it looks pretty similar - just other components)
I just scaffolded this model into controller.
This is start of validation and it seems like problem is somewhere here (at least VS says so).
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (MotherBoard == null) { throw new ArgumentNullException("Motherboard"); }
if (CPU == null) { throw new ArgumentNullException("CPU"); }
if (GPU == null) { throw new ArgumentNullException("GPU"); }
if (HDD == null) { throw new ArgumentNullException("HDD"); }
if (RAM == null) { throw new ArgumentNullException("RAM"); }
if (Power == null) { throw new ArgumentNullException("Power"); }
if (Case == null) { throw new ArgumentNullException("Case"); }
if (MotherBoard.CPU.ToUpper().Trim() != CPU.Socket.ToUpper().Trim())
{
yield return new ValidationResult("CPU socket does not match.", new[] { "cpu_id" });
}
}
When I create PC configuration without validation, it goes normally into database. But when I try this validation it says that CPU (in null test) is null and throws null exception. Screenshot from VS.
It never throws it on Motherboard but always on next item (on second item).
Upvotes: 1
Views: 672
Reputation: 1730
CPU seems to be treated by the entity framework as a navigation property. Without more information this suggests that you'll need to:
using System.Data.Entity
in whatever unit selects the model.Include(c => c.CPU)
before enumerating the query from the databaseIf that's truly a navigation property, as it appears, it may be lazily loaded as documented in the Entity Framework materials.
This means that even though the values seem to exist in the database the actual collection --or in your case, reference-- will be null in memory. So we tell the entity framework to "include" those items when we fetch:
var configuration = db.ConfigurationsOrSomething
.Include(c => c.CPU)
.Where(c => c.DeletedOrWhatever == false)
.ToList();
var cpu = configuration.CPU;
if(cpu == null)
Debug.WriteLine("Something else is the problem. :(");
You did say that you've seen the value in the database. We can't see the code that you've used to select the entity from the database --or anything else, if there is anything else. We also can see that CPU is another type you've defined and referenced. Your model looks like EF Code First / Table-per-Type if you need to know more about it along with a tutortial.
Note: I've re-read your comments in a new light. When you were asked if it was getting into the database you agreed that it was "created normally" without validation.
I'm now considering your entire setup to be a simple validation failure. If the validation says CPU is null... then CPU is null.
So: where is the code that you are using to create the new instance of this Configuration
entity? Are you simply not assigning a value to CPU?
Upvotes: 1