Puisque c'est encore un problème en EF 6.1.1 j'ai pensé que je pourrais fournir une autre réponse qui peut convenir à certaines personnes, en fonction de leur modèle exact exigences. Pour résumer le problème:
Vous devez utiliser un proxy pour le chargement paresseux.
La propriété vous êtes paresseux chargement est marqué Nécessaire.
Vous voulez modifier et enregistrer le proxy sans avoir à force de charger le paresseux références.
3 n'est pas possible avec le EF procurations (l'un d'eux), ce qui est une grave lacune à mon avis.
Dans mon cas, le paresseux propriété se comporte comme un type de valeur afin que sa valeur est fournie lorsque nous ajoutons de l'entité et n'a jamais changé. Je peux appliquer en sorte que ses setter protégés et de ne pas fournir une méthode de mise à jour, qui est, il doit être créé par le biais d'un constructeur, par exemple:
var myEntity = new MyEntity(myOtherEntity);
MyEntity a cette propriété:
public virtual MyOtherEntity Other { get; protected set; }
Donc EF ne sera pas effectuer une validation de cette propriété, mais je peux vous assurer qu'il n'est pas null dans le constructeur. C'est un scénario.
En supposant que vous ne souhaitez pas utiliser le constructeur de cette façon, vous pouvez toujours s'assurer de la validation à l'aide d'un attribut personnalisé, tels que:
[RequiredForAdd]
public virtual MyOtherEntity Other { get; set; }
Le RequiredForAdd attribut est un attribut personnalisé qui hérite de l'Attribut pas RequiredAttribute. Il n'a pas de propriétés ou méthodes en dehors de sa base.
Dans ma DB Contexte de la classe, j'ai un constructeur statique qui trouve toutes les propriétés avec ces attributs:
private static readonly List<Tuple<Type, string>> validateOnAddList = new List<Tuple<Type, string>>();
static MyContext()
{
FindValidateOnAdd();
}
private static void FindValidateOnAdd()
{
validateOnAddList.Clear();
var modelType = typeof (MyEntity);
var typeList = modelType.Assembly.GetExportedTypes()
.Where(t => t.Namespace.NotNull().StartsWith(modelType.Namespace.NotNull()))
.Where(t => t.IsClass && !t.IsAbstract);
foreach (var type in typeList)
{
validateOnAddList.AddRange(type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.CanRead)
.Where(pi => !(pi.GetIndexParameters().Length > 0))
.Where(pi => pi.GetGetMethod().IsVirtual)
.Where(pi => pi.GetCustomAttributes().Any(attr => attr is RequiredForAddAttribute))
.Where(pi => pi.PropertyType.IsClass && pi.PropertyType != typeof (string))
.Select(pi => new Tuple<Type, string>(type, pi.Name)));
}
}
Maintenant que nous avons une liste de propriétés dont nous avons besoin pour vérifier manuellement, nous pouvons remplacer la validation et de les valider manuellement, l'ajout de toutes les erreurs de la collection retournée à partir de la base du programme de validation:
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
return CustomValidateEntity(entityEntry, items);
}
private DbEntityValidationResult CustomValidateEntity(DbEntityEntry entry, IDictionary<object, object> items)
{
var type = ObjectContext.GetObjectType(entry.Entity.GetType());
// Always use the default validator.
var result = base.ValidateEntity(entry, items);
// In our case, we only wanted to validate on Add and our known properties.
if (entry.State != EntityState.Added || !validateOnAddList.Any(t => t.Item1 == type))
return result;
var propertiesToCheck = validateOnAddList.Where(t => t.Item1 == type).Select(t => t.Item2);
foreach (var name in propertiesToCheck)
{
var realProperty = type.GetProperty(name);
var value = realProperty.GetValue(entry.Entity, null);
if (value == null)
{
logger.ErrorFormat("Custom validation for RequiredForAdd attribute validation exception. {0}.{1} is null", type.Name, name);
result.ValidationErrors.Add(new DbValidationError(name, string.Format("RequiredForAdd validation exception. {0}.{1} is required.", type.Name, name)));
}
}
return result;
}
Notez que je ne m'intéresse qu'à valider pour un complément; si vous vouliez vérifier au cours de la Modifier, vous devez soit faire la force de la charge de la propriété ou de l'utilisation d'une commande Sql pour vérifier la valeur de clé étrangère (ne pourrait-il pas déjà quelque part dans le contexte)?
Parce que l'attribut Obligatoire a été supprimé, EF créer un nullable FK; pour vous assurer d'intégrité DB vous pourriez modifier la FKs manuellement dans un script Sql que vous exécutez sur votre base de données après qu'il a été créé. Cela permettra au moins de rattraper le Modifier avec null questions.