我正在尝试使用OrientDB-NET.binary,扩展它以提高开发团队的易用性。我正在尝试创建类似于dapper的语法,就像我们用于MSSQL和MySQL连接的那样。这应该使我们的开发团队更容易在两种技术之间进行交换。
我也喜欢我的扩展功能以进行交易。
这是我现在的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
是一个属性,可让我指定属性是否代表&#39; in&#39;边缘或者是一个&#39; out&#39;在顶点上的边缘。 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; }
}
然后我进口&#39;通过映射表中另一组条目映射数百Dependent
:
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)及其属性的正确值,273个ResidenceAddress记录(扩展PropertyAddress)使用正确的out和in rids扩展E),并使用正确的out和in rids扩展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()
,它立即处理记录创建,回滚不是一个选项。
在使用交易时,有没有办法正确创建边缘(而不是简单地插入记录)?
答案 0 :(得分: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 :(得分:1)
我最好把我的手作为OrientDBNet-Binary中OTransaction
课程的作者,并尽我所能提供帮助。
首先,出于性能原因,您肯定希望尝试使用OTransaction
而不是ODatabase.Create.Vertex
等 - 这就是为什么我首先添加了事务支持,因为它是10次以上比通过单个插入添加数据更快。
其次,编写OTransaction
类是为了支持我正在处理的生产项目,所以当我达到我自己的代码所需的功能级别时,我没有进一步推进它。这意味着以您正在进行的方式创建自定义边缘对象不是我在编写OTransaction
类时设计或测试的。
至于前进的想法 -