Поскольку это все еще проблема в EF 6.1.1, я подумал, что смогу дать другой ответ, который может подойти некоторым людям, в зависимости от их точных требований к модели.Чтобы подвести итог проблемы:
Для отложенной загрузки необходимо использовать прокси.
Свойство, для которого выполняется отложенная загрузка, помечено как обязательное.
Вы хотите изменить и сохранить прокси-сервер без принудительной загрузки отложенных ссылок.
3 невозможно с текущими прокси-серверами EF(любой из них), что, на мой взгляд, является серьезным недостатком.
В моем случае свойство lazy ведет себя как тип значения, поэтому его значение предоставляется при добавлении сущности и никогда не изменяется.Я могу применить это, сделав его установщик защищенным и не предоставив метод для его обновления, то есть он должен быть создан с помощью конструктора, например:
var myEntity = new MyEntity(myOtherEntity);
MyEntity имеет это свойство:
public virtual MyOtherEntity Other { get; protected set; }
Так что EF не выполнит проверку этого свойства, но я могу убедиться, что оно не равно нулю в конструкторе.Это один сценарий.
Предполагая, что вы не хотите использовать конструктор таким образом, вы все равно можете обеспечить проверку с помощью пользовательского атрибута, такого как:
[RequiredForAdd]
public virtual MyOtherEntity Other { get; set; }
Атрибут RequiredForAdd:пользовательский атрибут, который наследуется от атрибута , а не RequiredAttribute .Он не имеет никаких свойств или методов, кроме своих базовых.
В моем классе контекста БД у меня есть статический конструктор, который находит все свойства с этими атрибутами:
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)));
}
}
Теперь, когда у нас естьсписок свойств, которые нам нужно проверить вручную, мы можем переопределить проверку и вручную проверить их, добавив любые ошибки в коллекцию, возвращаемую из базового средства проверки:
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;
}
Обратите внимание, что меня интересует только проверка дляДобавлять;если вы хотите проверять также и во время изменения, вам нужно либо выполнить принудительную загрузку для свойства, либо использовать команду Sql для проверки значения внешнего ключа (разве это не должно быть где-то в контексте)?
Поскольку атрибут Required был удален, EF создаст обнуляемый FK;чтобы гарантировать целостность вашей БД, вы можете изменить FK вручную в сценарии Sql, который вы запускаете для своей базы данных после ее создания.Это, по крайней мере, поймает проблемы Modify with null.