我正在嘗試使用OrientDB-NET.binary,將其擴展以提高開發團隊的易用性。我試圖創建類似於dapper的語法,因爲這正是我們用於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()
,立即處理該記錄的創造,並回滾不一個選項。
有沒有辦法讓我的邊創建正確(而不是簡單插入爲記錄),同時仍然使用交易?
謝謝!不幸的是,輕量級的邊緣使「Traverse」的邏輯複雜化;我可以簡單地迭代遍歷* ...'結果集中的邊緣記錄,並獲得邊的兩端的ORID,而使用輕量級邊需要跟蹤完整的遍歷樹(可能是深度優先或寬度優先),其越複雜,給定頂點具有的鏈接越多。我們也很可能會在未來的邊緣包含自定義屬性,無論如何這需要重量級的邊緣。 – 2014-11-07 16:32:19
真遺憾。說實話,我看不出有什麼好的理由說明你爲什麼不應該使用當前的代碼 - 它可能只是一些愚蠢的東西。在服務器上打開協議調試消息可能是值得的,以查看發送到服務器的數據是否有任何錯誤([link](https://github.com/orientechnologies/orientdb/wiki/Network-Binary-Protocol #啓用調試的消息上的協議))。 如果您可以爲Orient.Tests項目創建一個單元測試,它會顯示您可以找到的最簡單的失敗案例(在TestTransactions.cs中),這將非常有幫助。 – RobinG 2014-11-10 09:00:41