EPR类企业管理系统

在我们现有系统基础上或全新开发,提供定制服务
为您的企业高效快速实施ERP,WMS,MES,CRM管理系统
全面管控物料仓库、销售业务、采购业务、仓库业务
生产过程、质量检验、组织架构、业务报表


定制
QQ:460-3528

开发
QQ群:3360-90194

源码
微信:136-3650-3721

代码和UI中的持久对象之间的关系

在设计业务模型时,可能有必要在业务对象之间设置特定的关系。本主题描述如何在XPO应用程序中的持久对象之间设置这些关系,并演示如何在UI中组织这些关系。

提示

要了解Entity Framework中实体之间的关系,请参阅“代码和UI中的实体之间的关系”主题。

关联的“许多”侧是集合属性,在WinForms和ASP.NET应用程序中使用ListPropertyEditor在Mobile应用程序中使用MobileLinkToListPropertyEditor在UI中显示。为了显示作为参考属性的“一侧”,在WinForms,ASP.NET和Mobile应用程序中分别使用LookupPropertyEditorASPxLookupPropertyEditorMobileLookupPropertyEditor。如果ExpandObjectMembersAttribute被施加到与所述参考属性ExpandObjectMembers.Never参数,ObjectPropertyEditor代替。每个对象集合都有一个单独的动作设置,具体取决于集合类型。您可以在模型编辑器中管理NewDeleteLinkUnlink Action的可见性。列表视图的设置AllowNewAllowDeleteAllowLink,或AllowUnlink属性为隐藏这些操作。

如果聚合了一个子对象(即,该对象被视为主对象的一部分并用AggregatedAttribute装饰),则将为其XPSested 对象创建一个XPNestedObjectSpace对象空间,因为在该对象的物理视图之前,不应将该对象物理保存到数据库中。所有者已保存。如果未聚合子对象(即,它可以单独存在),则将单独的XPObjectSpace用于其详细信息视图。嵌套列表视图(其中显示了详细信息集合中的对象)使用相同的主XPObjectSpace(无论聚合如何)。

本主题包括以下部分。

一对多(非汇总)

一个部门中可以包含许多联系人时,部门与联系人之间的关系说明了一对多的类型。在此示例中,Department对象包含一个子ContactsCollection集合,并且是其一对多关系的“一侧”。

NonAggregatedOneToMany_Win

NonAggregatedOneToMany_Web

NonAggregatedOneToMany_Mobile

显示ContactsCollection的列表视图伴随有一个New Action。此操作允许最终用户向现有的Department对象(包括当前对象)之一添加新的Contact对象。此外,还可以使用“链接”和“取消链接”操作,并允许您从另一个集合中添加和删​​除对Contact对象的引用。

非聚集对象在其自己的对象空间中创建。因此,可以在部门详细信息视图中创建的新联系人对象与父对象分开保存。

以下代码演示了如何实现这种类型的关系。

[DefaultClassOptions]
public class Contact : XPObject {
    //...
    private Department department;
    [Association("Department-Contacts")]
    public Department Department {
        get { return department; }
        set { SetPropertyValue(nameof(Department), ref department, value); }
    }
}
[DefaultClassOptions]
public class Department : XPObject {
    //...
    [Association("Department-Contacts")]
    public XPCollection<Contact> ContactsCollection {
        get { return GetCollection<Contact>(nameof(ContactsCollection)); }
    }
}

一对多(汇总)

假设一个联系人有一个便笺集合,这些便笺和它们的父联系人一起汇总。在这种情况下,Note对象声明与Contact对象的一对多关系的“一个”聚合面。

AggregatedOneToMany_Win

AggregatedOneToMany_Web

AggregatedOneToMany_Mobile

显示NotesCollection的列表视图伴随有New Action。此操作允许最终用户添加新的Note对象。请注意,在这种情况下,新Note对象的Contact属性将自动设置为当前Contact,并且该编辑器不会显示在UI中。

聚合的对象在父对象的Object Space中创建。因此,在“联系人详细信息”视图中创建的新便笺对象将在保存其父对象时被保存,并在其父对象被删除时被删除(级联删除机制)。

以下代码演示了如何实现这种类型的关系。

[DefaultClassOptions]
public class Contact : XPObject {
    //...
    [Association("Contact-Notes"), DevExpress.Xpo.Aggregated]
    public XPCollection<Note> NotesCollection {
        get { return GetCollection<Note>(nameof(NotesCollection)); }
    }
}
[DefaultClassOptions]
public class Note : XPObject {
    //...
    private Contact contact;
    [Association("Contact-Notes")]
    public Contact Contact {
        get { return contact; }
        set { SetPropertyValue(nameof(Contact), ref contact, value); }
    }
}

多对多

例如,每个联系人可以具有一组任务,并且每个任务可以分配给多个联系人。因此,ContactTask对象之间的关系称为“多对多”。

ManyToManyObject_Win

ManyToManyObject_Web

ManyToManyObject_Mobile

显示TasksCollection的列表视图附带链接操作。此操作允许最终用户添加对现有Task对象的引用。如果NewObjectViewController.LinkNewObjectToParentImmediately属性设置为true,则New Action不会应用于此集合。此行为符合“多对多”关系的独特概念。但是,您可以在“链接操作”的弹出窗口中创建一个新的任务

取消链接操作也提供了TasksCollection。此操作允许最终用户从集合中删除对Task对象的引用。

以下代码演示了如何实现这种类型的关系。

[DefaultClassOptions]
public class Contact : XPObject {
    //...
    [Association("Contacts-Tasks")]
    public XPCollection<Task> TasksCollection {
        get { return GetCollection<Task>(nameof(TasksCollection)); }
    }
}
[DefaultClassOptions]
public class Task : XPObject {
    //...
    [Association("Contacts-Tasks")]
    public XPCollection<Contact> ContactsCollection {
        get { return GetCollection<Contact>(nameof(ContactsCollection)); }
    }
}

一对一

如果每个联系人只能有一个唯一的地址,并且一个地址不能分配给多个联系人,则此关系为一对一。

OneToOneObject_Win

OneToOneObject_Web

OneToOneObject_Mobile

这种关系没有提供收集方面的信息。请注意,在这种情况下,新Address对象的Contact属性将自动设置为当前Contact。

以下代码演示了如何实现这种类型的关系。

[DefaultClassOptions]
public class Contact : XPObject {
    //...
    [Aggregated]
    private Address address;
    public Address Address{
        get { return address; }
        set {
            if (address == value) return;
            Address prevAddress = address;
            address = value;
            if (IsLoading) return;
            if (prevAddress!= null && prevAddress.Contact == this)
                prevAddress.Contact = null;
            if (address != null)
                address.Contact = this;
            OnChanged(nameof(Address));
        }
    }
}
[DefaultClassOptions]
public class Address : XPObject {
    //...
    Contact contact = null;
    public Contact Contact {
        get { return contact; }
        set {
            if (contact == value)
                return;
            Contact prevContact = contact;
            contact = value;
            if (IsLoading) return;
            if (prevContact != null && prevContact.Address == this)
                prevContact.Address = null;
            if (contact != null)
                contact.Address = this;
            OnChanged(nameof(Contact));
        }
    }
}
相关文章

转载保留此链接,注明出处