Нарушение кратности нарушено (в XAF, когда не создан доступ к selectedObject.ObjectSpace.ModifiedObjects.Count.)
Резюме вопроса:
Почему можно было бы обойти "нарушенное ограничение множественности", введя следующую строку кода?
var numModifiedObjects =createdObject.ObjectSpace.ModifiedObjects.Count;
Есть ли настройка, которая сделает ненужным обходной путь?
Предпосылки проблемы, сопровождаемой обходным путем:
В моем winforms xaf, проекте EF6.2 Code First у меня есть следующий бизнес-объект, который сам ссылается.
[NavigationItem("Main")]
public class H2Category : IHCategory
{
public H2Category()
{
Children = new BindingList<H2Category>();
}
[Browsable(false)]
public Int32 ID { get; protected set; }
public String Name { get; set; }
public H2Category Parent { get; set; }
public virtual IList<H2Category> Children { get; set; }
[NotMapped, Browsable(false), RuleFromBoolProperty("H2CategoryCircularReferences", DefaultContexts.Save, "Circular refrerence detected. To correct this error, set the Parent property to another value.", UsedProperties = "Parent")]
public Boolean IsValid
{
get
{
H2Category currentObj = Parent;
while (currentObj != null)
{
if (currentObj == this)
{
return false;
}
currentObj = currentObj.Parent;
}
return true;
}
}
IBindingList ITreeNode.Children => Children as IBindingList;
ITreeNode IHCategory.Parent
{
get => Parent as IHCategory;
set => Parent = value as H2Category;
}
ITreeNode ITreeNode.Parent => Parent as ITreeNode;
}
и в dbContext OnModelCreating я использую
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<H2Category>().HasMany(x => x.Children).WithOptional(x => x.Parent);
Parent_id);
База данных выглядит правильно в обозревателе объектов SQL Server
и данные выглядят правильно.
В XAF Treeview, когда пользователь добавляет дочернюю запись, я хочу, чтобы родитель нового дочернего элемента был установлен на текущую запись.
Для этого я использую NewObjectViewController
public partial class H2CategoryController : ViewController
{
private NewObjectViewController controller;
public H2CategoryController()
{
InitializeComponent();
TargetObjectType = typeof(H2Category);
}
protected override void OnActivated()
{
controller = Frame.GetController<NewObjectViewController>();
controller.ObjectCreated += controller_ObjectCreated;
base.OnActivated();
}
private void controller_ObjectCreated(object sender, ObjectCreatedEventArgs e)
{
var createdObject = e.CreatedObject as H2Category;
var currentObject = View.CurrentObject as H2Category;
// inspection here shows that currentObject and createdObject are different but they have the same proxy
var s = $"created object Id is {createdObject.ID} current object id is {currentObject.ID}";
Console.WriteLine(s);
var propertyCollectionSource = (View as ListView)?.CollectionSource as PropertyCollectionSource;
if (!(propertyCollectionSource?.MasterObject is H2Category master)) return;
createdObject.Parent = master;
createdObject.Name = "t";
master.Children.Add(createdObject);
Console.WriteLine(master.ID);
}
protected override void OnDeactivated()
{
controller.ObjectCreated += controller_ObjectCreated;
base.OnDeactivated();
}
}
Как только пользователь начинает вводить новую запись, появляется следующая ошибка
Multiplicity constraint violated. The role 'H2Category_Children_Source' of the relationship 'SBD.GL.Module.BusinessObjects.H2Category_Children' has multiplicity 1 or 0..1.
at System.Data.Entity.Core.Objects.EntityEntry.AddDetectedRelationship[T](Dictionary`2 relationships, T relatedObject, RelatedEnd relatedEnd)
at System.Data.Entity.Core.Objects.EntityEntry.AddRelationshipDetectedByGraph(Dictionary`2 relationships, Object relatedObject, RelatedEnd relatedEndFrom, Boolean verifyForAdd)
at System.Data.Entity.Core.Objects.EntityEntry.DetectChangesInRelationshipsOfSingleEntity()
at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChangesInNavigationProperties(IList`1 entries)
at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChanges()
at System.Data.Entity.Core.Objects.ObjectContext.DetectChanges()
at DevExpress.ExpressApp.EF.EFObjectSpace.DetectChanges()
at DevExpress.ExpressApp.EF.EFObjectSpace.GetModifiedObjects()
at DevExpress.ExpressApp.EF.EFObjectSpace.get_ModifiedObjects()
at DevExpress.ExpressApp.Win.SystemModule.CustomCollectModifiedObjectsEventArgs.CollectModifiedObjects(Boolean checkObjectSpaceIsModified)
at DevExpress.ExpressApp.Win.SystemModule.LockController.GetModifiedObjects()
at DevExpress.ExpressApp.Win.SystemModule.LockController.CheckLocking(LockController controller)
at DevExpress.ExpressApp.Win.SystemModule.LockController.CheckLocking(Object obj)
at DevExpress.ExpressApp.Win.SystemModule.LockController.ViewObjectSpace_ObjectChanged(Object sender, ObjectChangedEventArgs e)
at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
at DevExpress.ExpressApp.BaseObjectSpace.OnObjectChanged(ObjectChangedEventArgs args)
at DevExpress.ExpressApp.EF.EFObjectSpace.SetModified(Object obj, ObjectChangedEventArgs args)
at DevExpress.ExpressApp.BaseObjectSpace.SetModified(Object obj, IMemberInfo memberInfo)
at DevExpress.ExpressApp.DetailView.Editor_ControlValueChanged(Object sender, EventArgs e)
at System.EventHandler.Invoke(Object sender, EventArgs e)
at DevExpress.ExpressApp.Editors.PropertyEditor.OnControlValueChanged()
at DevExpress.ExpressApp.Win.Editors.DXPropertyEditor.Editor_EditValueChanged(Object sender, EventArgs e)
at System.EventHandler.Invoke(Object sender, EventArgs e)
at DevExpress.XtraEditors.Repository.RepositoryItem.RaiseEditValueChangedCore(EventArgs e)
at DevExpress.XtraEditors.Repository.RepositoryItem.RaiseEditValueChanged(EventArgs e)
at DevExpress.XtraEditors.BaseEdit.RaiseEditValueChanged()
at DevExpress.XtraEditors.BaseEdit.OnEditValueChanged()
at DevExpress.XtraEditors.TextEdit.OnEditValueChanged()
at DevExpress.XtraEditors.BaseEdit.OnEditValueChanging(ChangingEventArgs e)
at DevExpress.XtraEditors.TextEdit.OnEditValueChanging(ChangingEventArgs e)
at DevExpress.XtraEditors.BaseEdit.set_EditValue(Object value)
at DevExpress.XtraEditors.TextEdit.OnMaskBox_ValueChanged(Object sender, EventArgs e)
at DevExpress.XtraEditors.Mask.MaskBox.RaiseEditTextChanged()
at DevExpress.XtraEditors.Mask.MaskBox.MaskStrategy.SimpleStrategy.DoAfterTextChanged(EventArgs e)
at DevExpress.XtraEditors.Mask.MaskBox.OnTextChanged(EventArgs e)
at System.Windows.Forms.TextBoxBase.WmReflectCommand(Message& m)
at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
at System.Windows.Forms.TextBox.WndProc(Message& m)
at DevExpress.XtraEditors.Mask.MaskBox.BaseWndProc(Message& m)
at DevExpress.XtraEditors.Mask.MaskBox.MaskStrategy.SimpleStrategy.DoWndProc(Message& m)
at DevExpress.XtraEditors.Mask.MaskBox.WndProc(Message& m)
at DevExpress.XtraEditors.TextBoxMaskBox.WndProc(Message& msg)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Я отмечаю, что значения отладки выглядят правильно, когда я устанавливаю родителя
Но я смущен тем, что все объекты H2Category имеют одинаковое значение прокси.
Я спрашивал об этой проблеме в Dev Express, но спрашиваю здесь, так же как это связано с Entity Framework.
[Обновление-Работа вокруг]
Я добавил интерфейс IObjectSpaceLink к бизнес-объекту. Это предоставляет ObjectSpace как свойство бизнес-объекта.
Когда я поместил разрыв в методе controller_ObjectCreated, я смог увидеть, что свойство ModifiedObjects показывает ошибку
Я обнаружил, что если я присваиваю переменную creatObject.ObjectSpace.ModifiedObjects.Count, то проблема не возникает.
private void controller_ObjectCreated(object sender, ObjectCreatedEventArgs e)
{
var createdObject = e.CreatedObject as H2Category;
var numModifiedObjects =createdObject.ObjectSpace.ModifiedObjects.Count;
var currentObject = View.CurrentObject as H2Category;
var s = $"created object Id is {createdObject.ID} current object id is {currentObject.ID}";
var propertyCollectionSource = (View as ListView)?.CollectionSource as PropertyCollectionSource;
if (!(propertyCollectionSource?.MasterObject is H2Category master)) return;
var m = e.ObjectSpace.GetObject(master);
createdObject.Parent = m;
createdObject.Name = "t";
m.Children.Add(createdObject);
numModifiedObjects = createdObject.ObjectSpace.ModifiedObjects.Count;
Console.WriteLine(master.ID);
}
Я пытался отключить создание прокси, но это не помогло.
1 ответ
От ответа поддержки Dev Express.
Отношения работают неправильно в моем проекте из-за ошибки в моем H2Category
учебный класс. Свойство Parent должно быть объявлено виртуальным.
Также мой ICategoryController
конфликтует со встроенным TreeNodeController
, Этот контроллер также подписывается на NewObjectViewController.ObjectCreated
событие и ссылки недавно созданный ITreeNode
объект с родительским узлом, выбранным в представлении списка источников. По умолчанию объекты связываются при сохранении изменений. Чтобы связать новый объект сразу после создания, установите NewObjectViewController.LinkNewObjectToParentImmediately
собственность на true
,