如何使用多个主键 table 动态创建 DevExpress XPO?

How to create DevExpress XPO dynamically with multiple primary-keys table?

我尝试这个主题中的示例 https://github.com/DevExpress-Examples/XPO_how-to-create-an-xpclassinfo-descendant-to-dynamically-build-a-persistent-class-structure-e1729

但它只适用于单个主键表。所以我搜索了更多发现这个: https://github.com/DevExpress-Examples/XPO_how-to-create-persistent-classes-mapped-to-tables-with-a-composite-primary-key-at-runtime-e4606

但是有很大的不同,我认为它不令人满意,因为它谈到复合键(一个键有很多列) 所以我只需要一个从 SQL -Server Table 动态创建 XPO 的例子: 我的 Table 架构如下

然后 XPOCollectionSource 在服务器模式下绑定到网格...这就是我所需要的。

我使用的代码

XPServerCollectionSource GetServerModeSourceForTable(IDbConnection connection, string tableName) {  
    XPDictionary dict = new ReflectionDictionary();  
    XPClassInfo classInfo = dict.CreateClass(dict.QueryClassInfo(typeof(LiteDataObject)),  
        tableName);  
    DBTable[] tables = ((ConnectionProviderSql)XpoDefault.GetConnectionProvider(connection,  
        AutoCreateOption.None)).GetStorageTables(tableName);  
    foreach (DBColumn col in tables[0].Columns) {  
        XPMemberInfo member = classInfo.CreateMember(col.Name, DBColumn.GetType(  
            col.ColumnType));  
        if (tables[0].PrimaryKey.Columns.Contains(col.Name))  
            member.AddAttribute(new KeyAttribute());  
    }  
    return new XPServerCollectionSource(new Session(XpoDefault.GetDataLayer(  
        connection, dict, AutoCreateOption.None)), classInfo);  
}  

一目了然。如何将 XPServerCollectionSource 与动态创建的 XPO 对象一起使用。有两个主键。

我不知道这是否是您想要的,但我会使用 XPInstantFeedbackSource.

分享我的代码

您可以在 How To Implement The Instant Feedback Mode Xpo

获取更多信息

XPLiteObject LogXPOModel

[Persistent("log.t_log")]
public class LogXPOModel : XPLiteObject
{
    [Key, DevExpress.Xpo.DisplayName("id")]
    public long id { get; set; }

    [Key, DevExpress.Xpo.DisplayName("recv_time")]    
    public long recv_time

    ...
}

Window 主窗口

public class MainWindow : Window
{
    public XPInstantFeedbackSource SqliteXPInstantFeedbackSource

    public MainWindow() {
        ...
        SqliteXPInstantFeedbackSource = new XPInstantFeedbackSource();
        SqliteXPInstantFeedbackSource.ObjectType = typeof(LogXPOModel);
        SqliteXPInstantFeedbackSource.ResolveSession += SqliteXPInstantFeedbackSource_ResolveSession;
        SqliteXPInstantFeedbackSource.DismissSession += SqliteXPInstantFeedbackSource_DismissSession;
        View.Grid.ItemsSource = SqliteXPInstantFeedbackSource;
    }
    
    ...
}

就像那样——我的 table 有两个钥匙;而且,它不会产生任何问题。

https://github.com/DevExpress-Examples/XPO_how-to-create-persistent-classes-mapped-to-tables-with-a-composite-primary-key-at-runtime-e4606/blob/19.2.7%2B/CS/XpoConsoleApplication/XPComplexCustomMemberInfo.cs

这是class必须使用的。谁需要更多详细信息。我可以免费帮助他

实现可以像这样:

[NonPersistent]
public class XPDynamicObject  : XPLiteObject
{
    public XPDynamicObject(Session session) : base(session) {}
    public XPDynamicObject(Session session, XPClassInfo classInfo) : base(session, classInfo) { }
}


       Button_Click or any event :

       XPDynamicObject.AutoSaveOnEndEdit = false;

        ReflectionDictionary dic = new ReflectionDictionary();
        var classInfo = dic.CreateClass(dic.GetClassInfo(typeof(XPDynamicObject)), "general.users");

        // WE MUST get schema from database .... via ConnectionProviderSql this is only way 
        var provider = XpoDefault.GetConnectionProvider(MSSqlConnectionProvider.GetConnectionString("(local)", "testdb"), AutoCreateOption.None) as ConnectionProviderSql;

        
        // Composite Key - this is only way to add composite key dynamically
        XPComplexCustomMemberInfo user_key = new 
        XPComplexCustomMemberInfo(classInfo, "user_key", typeof(object), new KeyAttribute(), new PersistentAttribute(), new BrowsableAttribute(false));
        user_key.AddSubMember("user_brn", typeof(int), new PersistentAttribute("user_brn"));
        user_key.AddSubMember("user_num", typeof(int), new PersistentAttribute("user_num"));

        var user_name = classInfo.CreateMember("user_name", typeof(string));
        user_name.AddAttribute(new PersistentAttribute("user_name"));
        

        dal = new SimpleDataLayer(dic, provider);

        XPServerCollectionSource xpServerCollectionSource = new XPServerCollectionSource(session, classInfo); // XPServerCollectionSource Only Editable server-mode datasource via ALlowNew, AllowEdit, AllowRemove properties

GridControl.DataSource = xpServerCollectionSource ;

完全作弊 Sheet(Design-Time 和 Run-Time XPO)

要按关键字或条件搜索 Object,请使用以下内容:

编辑:2021-05-24

对于那些询问与复合键关联的人。这真是一场噩梦。默认情况下 Xpo 不提供。相反,您可以在 child-class 中使用 Session.GetObjectByKey() 并在 parent class 中使用新的 XPCollection。但实际上,使用人工密钥的本机方式有点慢。

At a glance: Use Artifcial / Single Key Column for Better any ORM compatibility. Otherwise It will be nightmare in database later. If you for example support another or replace current ORM.

这是与复合键关联的代码。 (请注意,您需要像上面的图片一样动态转换它。您可能需要创建自定义 XPMemberInfo 并将 GetValue() 覆盖为 return Session.GetObjectByKey() 并创建新的 XPCollection。(真的很糟糕Xpo 有史以来最糟糕的 non-supported。所以 Composite-Keys 在技术上是不好的方法,除非你需要创建 Single Table 将其绑定到网格。EX:- SalesOrderDetail table 不没有更多 child tables)

[Persistent("users")]
public class user : XPLiteObject
{
    public user(Session session) : base(session) { }
    public user(Session session, XPClassInfo classInfo) : base(session, classInfo) { }

    [Key, Persistent]
    public user_key user_key { get; set; }
    [Persistent("user_name")]
    public string user_name { get; set; }

    private XPCollection<Trans> _trans;
    public XPCollection<Trans> trans
    {
        get
        {
            if (_trans == null)
                _trans = new XPCollection<Trans>(Session, CriteriaOperator.Parse($"user_brn = {user_key.user_brn} AND user_num = {user_key.user_num}"));
            return _trans;
        }
    }

}

public class Trans : XPLiteObject
{
    public Trans(Session session) : base(session) { }
    public Trans(Session session, XPClassInfo classInfo) : base(session, classInfo) { }

    [Key,Persistent("TransID")]
    public int TransID { get; set; }

    public int user_brn { get; set; }
    public int user_num { get; set; }

    public user user
    {
        get
        {
            var key = new user_key();
            key.user_brn = 1;
            key.user_num = 3;
            var obj = Session.GetObjectByKey<user>(key, true);
            return obj;
        }
    }
}

// Composite-Key
public struct user_key
{
    [Persistent("user_brn")]
    public int user_brn { get; set; }
    [Persistent("user_num")]
    public int user_num { get; set; }
}

来自上述型号的动态 run-time 版本:

    class XPCompositeAssociationMemberInfo : XPCustomMemberInfo
    {
        public XPCompositeAssociationMemberInfo(XPClassInfo owner, string propertyName, Type propertyType, XPClassInfo referenceType, bool nonPersistent, bool nonPublic) : base(owner, propertyName, propertyType, referenceType, nonPersistent, nonPublic)
        {
        }

        public override object GetValue(object theObject)
        {
            XPDynamicObject val = theObject as XPDynamicObject;
            if(val != null)
            {
                var user_num = val.GetMemberValue("user_num");
                IdList vals = new IdList();
                vals.Add(1);
                vals.Add(user_num);
                return val.Session.GetObjectByKey(ReferenceType, vals);
            }
            return val;
        }
    }


  XPDynamicObject.AutoSaveOnEndEdit = false;

        ReflectionDictionary dic = new ReflectionDictionary();
        var userClassInfo = dic.CreateClass(dic.GetClassInfo(typeof(XPDynamicObject)), "users");

        // WE MUST get schema from database .... via ConnectionProviderSql this is only way 
        var provider = XpoDefault.GetConnectionProvider(MSSqlConnectionProvider.GetConnectionString("(local)", "testdb"), AutoCreateOption.None) as ConnectionProviderSql;
        //DBTable Table = provider.GetStorageTables("users")[0];
        
        // Composite Key - this is only way to add composite key dynamically
        XPComplexCustomMemberInfo user_key = new XPComplexCustomMemberInfo(userClassInfo, "user_key", typeof(object), new KeyAttribute(), new PersistentAttribute(), new BrowsableAttribute(false));
        user_key.AddSubMember("user_brn", typeof(int), new PersistentAttribute("user_brn"));
        user_key.AddSubMember("user_num", typeof(int), new PersistentAttribute("user_num"));
        
        var user_name = userClassInfo.CreateMember("user_name", typeof(string));
        user_name.AddAttribute(new PersistentAttribute("user_name"));

        var transClassInfo = dic.CreateClass(dic.GetClassInfo(typeof(XPDynamicObject)), "Trans");
        var TransID = transClassInfo.CreateMember("TransID", typeof(int), new KeyAttribute());
        var user_brn = transClassInfo.CreateMember("user_brn", typeof(int));
        var user_num = transClassInfo.CreateMember("user_num", typeof(int));
        XPCompositeAssociationMemberInfo userMI = new XPCompositeAssociationMemberInfo(transClassInfo, "user", typeof(object), userClassInfo, true, false);



        dal = new SimpleDataLayer(dic, provider);            
        Session session = new Session(dal);
        XPServerCollectionSource xpServerCollectionSource = new XPServerCollectionSource(session, transClassInfo); // XPServerCollectionSource Only Editable server-mode datasource via ALlowNew, AllowEdit, AllowRemove properties                        
        xpServerCollectionSource.DisplayableProperties = "TransID;user.user_key.user_num;user.user_name";

最后,重要!

Its really very very hard to achieve Composite-Keys cases at runtime in any Xpo. Instead replace with Single Column Key(Identity or Artificial one. GUID one etc.)