2014-11-06 14 views
1

我正在嘗試使用OrientDB-NET.binary,將其擴展以提高開發團隊的易用性。我試圖創建類似於的語法,因爲這正是我們用於MSSQL和MySQL連接的語法。這應該使我們的開發團隊更容易在兩種技術之間進行交換。在交易中使用OrientDB-NET.binary創建邊線

我還想讓我的擴展功能與交易。

這裏是我的Insert延伸,因爲它現在是:

public static void Insert<T>(this ODatabase db, T model, 
    OTransaction transaction) where T : ABaseModel, new() 
{ 
    InsertHelper(db, model, transaction, new List<object>()); 
} 

private static void InsertHelper<T>(ODatabase db, T model, 
    OTransaction transaction, ICollection<object> exclude, ORID parent = null) 
     where T : ABaseModel, new() 
{ 
    // Avoid following loops into a stack overflow 
    if (exclude.Contains(model)) return; 
    exclude.Add(model); 

    ODocument record = new ODocument(); 
    record.OClassName = model.GetType().Name; 
    PropertyInfo[] properties = model.GetType().GetProperties(
     BindingFlags.Public | BindingFlags.Instance | 
     BindingFlags.SetProperty | BindingFlags.GetProperty); 
    ICollection<PropertyInfo> linkableProperties = new List<PropertyInfo>(); 
    foreach (PropertyInfo prop in properties) 
    { 
     if (reservedProperties.Contains(prop.Name)) continue; 

     OProperty aliasProperty = prop.GetCustomAttributes(typeof(OProperty)) 
      .Where(attr => ((OProperty)attr).Alias != null) 
      .FirstOrDefault() as OProperty; 
     string name = aliasProperty == null ? prop.Name : aliasProperty.Alias; 

     // Record properties of model, but store properties linking to other 
     // vertex classes for later 
     if (typeof(ABaseModel).IsAssignableFrom(prop.PropertyType)) 
     { 
      linkableProperties.Add(prop); 
     } 
     else 
     { 
      record[name] = prop.GetValue(model); 
     } 
    } 

    transaction.Add(record); 
    model.ORID = record.ORID; 

    foreach (PropertyInfo prop in linkableProperties) 
    { 
     ORID outV, inV; 
     ABaseModel propValue = prop.GetValue(model) as ABaseModel; 
     if (!exclude.Select(ex => ex is ABaseModel ? ((ABaseModel)ex).ORID : 
       ORID_DEFAULT).Contains(propValue.ORID)) 
     { 
      MethodInfo insertMethod = typeof(DatabaseExtensions) 
       .GetMethod("InsertHelper", BindingFlags.NonPublic | 
        BindingFlags.Static).MakeGenericMethod(propValue.GetType()); 
      insertMethod.Invoke(null, 
       new object[] { 
        db, propValue, transaction, exclude, model.ORID 
       }); 
     } 
     outV = model.ORID; 
     inV = propValue.ORID; 

     OEdgeAttribute edgeType = 
      prop.GetCustomAttributes(typeof(OEdgeAttribute)) 
       .FirstOrDefault() as OEdgeAttribute; 
     OProperty propertyAlias = prop.GetCustomAttributes(typeof(OProperty)) 
      .Where(p => ((OProperty)p).Alias != null) 
      .FirstOrDefault() as OProperty; 
     string alias = propertyAlias == null ? prop.Name : propertyAlias.Alias; 
     if (edgeType != null) 
     { 
      OEdge link = new OEdge(); 
      link.OClassName = alias; 
      link["out"] = outV; 
      link["in"] = inV; 
      if(edgeType.IsInV) 
      { 
       ORID tmp = link.OutV; 
       link["out"] = link.InV; 
       link["in"] = tmp; 
      } 

      // Do not create an edge if there is an edge already 
      // connecting these vertices 
      IEnumerable<Tuple<ORID,ORID>> excludedLinks = exclude 
       .Select(ex => ex is OEdge ? 
        new Tuple<ORID,ORID>(((OEdge)ex).OutV,((OEdge)ex).InV) : 
        new Tuple<ORID,ORID>(ORID_DEFAULT, ORID_DEFAULT)); 
      if (excludedLinks.Contains(
       new Tuple<ORID, ORID>(link.OutV, link.InV))) continue; 

      exclude.Add(link); 
      transaction.Add(link); 
     } 
    } 
} 

ABaseModel旨在通過所有的模型類在我的應用程序擴展的抽象類。 OEdgeAttribute是一個屬性,可讓我指定屬性是否代表頂點上的「入」邊或「出」邊。 ORID_DEFAULT等於new ORID()

上述擴展方法工作得很好......主要是。從表中的另一組條目由映射

public class Person : ABaseModel 
{ 
    [OProperty(Alias = "ResidenceAddress")] 
    [OEdge(IsOutV = true)] 
    public Address Residence { get; set; } 
    [OProperty(Alias = "ShippingAddress")] 
    [OEdge(IsOutV = true)] 
    public Address Shipping { get; set; } 
} 

public class Dependent : Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    // etc... 
} 

public class Address : ABaseModel 
{ 
    public string AddressLine1 { get; set; } 
    public string AddressLine2 { get; set; } 
    // etc... 

    [OProperty(Alias = "PropertyAddress")] 
    public Person Resident { get; set; } 
} 

我再「進口」幾百Dependent S::使用下面的模型類

OClient.CreateDatabasePool("127.0.0.1", 2424, "persephone", ODatabaseType.Graph, 
    "admin", "admin", 10, "Persephone"); 

// PersephoneConnection has access to ODatabase and OTransaction, 
// and some methods which dispatch to them 
IPersephoneConnection persephone = new PersephoneConnection(); 
persephone.BeginTransaction(); 

// Traverse is a functioning extension method which essentially calls 
// `traverse * from {0}` and maps the result to model objects 
IEnumerable<tmpED> eds = persephone.Connection.Traverse<tmpED>("tmpED"); 
foreach (tmpED model in eds) 
{ 
    Dependent dep = new Dependent 
    { 
     FirstName = model.firstname, 
     LastName = model.lastname, 
     // etc... 
    }; 

    Address residence = new Address 
    { 
     AddressLine1 = model.addres_line1, 
     AddressLine2 = model.address_line2, 
     // etc... 

     Resident = dep 
    }; 
    dep.Residence = residence; 

    Address shipping = new Address 
    { 
     AddressLine1 = model.shippingaddress_line1, 
     AddressLine2 = model.shippingaddres_line2, 
     // etc... 

     Resident = dep 
    }; 
    dep.Shipping = shipping; 

    persephone.Connection.Insert(dep, persephone.Transaction); 
} 
persephone.Commit(); 
persephone.Dispose(); 

運行此代碼後,我的數據庫包含273依賴記錄(擴展V的Person),其屬性的正確值,546地址記錄(擴展V),其屬性的值正確,273AddressAddress記錄(擴展E的PropertyAddress),以及正確的外出和撤銷,以及273 ShippingAddress記錄(擴展PropertyAddress)與正確的輸出和擺脫。

但是,依賴者或地址都不能看到連接它們的邊緣。 traverse * #29:0帶來了第一個依賴,但沒有提出他的住所或送貨地址。 select expand(out('ResidenceAddress')) from Dependent返回一個空的結果集。

一些修修補補之後,似乎這種情況的原因是因爲OTransaction.Add基本上執行insert into {0}當事務被提交,而不是create vertex {0}create edge {0}

我當然可以改變我的代碼,使用ODatabase.Create.Vertex()ODatabase.Create.Edge()代替OTransaction.Add(),但不是在這種情況下,提交事務,我得叫OSqlCreateEdge.Run()OSqlCreateVertex.Run(),立即處理該記錄的創造,並回滾不一個選項。

有沒有辦法讓我的邊創建正確(而不是簡單插入爲記錄),同時仍然使用交易?

回答

2

創建通過事務厚邊,您需要爲響應文件

之間的正確鏈接設置

這裏

看例子
 var v1 = new ODocument { OClassName = "TestVertex" }; 
     v1.SetField("Name", "First"); 
     v1.SetField("Bar", 1); 

     var v2 = new ODocument { OClassName = "TestVertex" }; 
     v2.SetField("Name", "Second"); 
     v2.SetField("Bar", 2); 

     var e1 = new ODocument { OClassName = "TestEdge" }; 
     e1.SetField("Weight", 1.3f); 

     // Add records to the transaction 
     _database.Transaction.Add(v1); 
     _database.Transaction.Add(v2); 
     _database.Transaction.Add(e1); 

     // link records 
     v1.SetField("in_TestEdge", e1.ORID); 
     v2.SetField("out_TestEdge", e1.ORID); 
     e1.SetField("in", v1.ORID); 
     e1.SetField("out", v2.ORID); 

     _database.Transaction.Commit(); 
1

我最好把我的手放在OrientDBNet-Binary中作爲OTransaction類的作者,並給予我可以提供的幫助。

首先,您肯定想嘗試使用OTransaction而不是ODatabase.Create.Vertex等,因爲性能方面的原因 - 這就是爲什麼我首先增加了事務支持的原因,因爲它比通過單獨插入添加數據的速度快10倍以上。

其次,編寫OTransaction類是爲了支持我正在開發的生產項目,所以當我達到我自己的代碼所需的功能級別時,我沒有再向前推它。這意味着以您所做的方式創建自定義邊界對象並不是我在編寫OTransaction類時所設計或測試的內容。

至於想法前進 - 如果你沒有在你的邊緣使用自定義屬性

  • ,那麼就沒有必要創建擺在首位的邊緣對象,只需設置ORIDs上的頂點在鏈接的每一端指向彼此(基本上使用輕量級邊)
  • 如果您覺得能夠將代碼更改爲OrientDBNet-Binary項目,那麼可以隨意這樣做,並提交一個包含更改的拉取請求。
+0

謝謝!不幸的是,輕量級的邊緣使「Traverse」的邏輯複雜化;我可以簡單地迭代遍歷* ...'結果集中的邊緣記錄,並獲得邊的兩端的ORID,而使用輕量級邊需要跟蹤完整的遍歷樹(可能是深度優先或寬度優先),其越複雜,給定頂點具有的鏈接越多。我們也很可能會在未來的邊緣包含自定義屬性,無論如何這需要重量級的邊緣。 – 2014-11-07 16:32:19

+0

真遺憾。說實話,我看不出有什麼好的理由說明你爲什麼不應該使用當前的代碼 - 它可能只是一些愚蠢的東西。在服務器上打開協議調試消息可能是值得的,以查看發送到服務器的數據是否有任何錯誤([link](https://github.com/orientechnologies/orientdb/wiki/Network-Binary-Protocol #啓用調試的消息上的協議))。 如果您可以爲Orient.Tests項目創建一個單元測試,它會顯示您可以找到的最簡單的失敗案例(在TestTransactions.cs中),這將非常有幫助。 – RobinG 2014-11-10 09:00:41