Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用于模型的OrientDB-NET.binary_C#_Orientdb - Fatal编程技术网

C# 用于模型的OrientDB-NET.binary

C# 用于模型的OrientDB-NET.binary,c#,orientdb,C#,Orientdb,我的团队感兴趣的是将一个现有的MySQL数据库迁移到OrientDB,这个数据库非常丑陋,索引也很差。由于我们的应用程序是用C编写的,所以我正在研究从C应用程序中访问数据库的能力 我发现作为一个图书馆,我可以做我想做的事情,然而,我很难让它做我想做的一切。根据OrientDB文档,我正在测试的数据库非常简单: 创建类Person扩展V 创建类汽车扩展V 创建类国家/地区扩展V 创建类E 创建类生命扩展E 创建property.out链接人 在链接车中创建属性 创建property Lifes.o

我的团队感兴趣的是将一个现有的MySQL数据库迁移到OrientDB,这个数据库非常丑陋,索引也很差。由于我们的应用程序是用C编写的,所以我正在研究从C应用程序中访问数据库的能力

我发现作为一个图书馆,我可以做我想做的事情,然而,我很难让它做我想做的一切。根据OrientDB文档,我正在测试的数据库非常简单:

创建类Person扩展V 创建类汽车扩展V 创建类国家/地区扩展V 创建类E 创建类生命扩展E 创建property.out链接人 在链接车中创建属性 创建property Lifes.out链接人 在链接国家/地区创建财产生命 alter property Owns.out必填=true alter property Owns.in必填=true alter property lifes.out必填=true alter property Lives.in强制=true 在自己的唯一目录中创建索引唯一 在Livesout unique上创建索引uniquelifes 当我查询数据库中的气味文档时,我得到了大量的预期信息:

OClient.CreateDatabasePool127.0.0.12424,cars, 图,管理,管理,10,汽车; 使用ODatabase db=新的ODatabaseCars { var结果=db.Select.FormCountry.ToList; 结果中的foreach var项 { 项中的foreachvar键。键 { Console.WriteLinekey; 如果项[键]是IEnumerable { 项[key]中的foreach var元素为IEnumerable { Console.WriteLine+元素; } } 其他的 { Console.WriteLine+项[键]; } } Console.WriteLine; } } Console.ReadKey; 输出:

@奥里德 15:0 @过度兴奋 5. @打字 文件 @奥克拉西德 0 @奥克拉斯名称 国 名称 英国 in_生活 16:0 @奥里德 15:1 @过度兴奋 3. @打字 文件 @奥克拉西德 0 @奥克拉斯名称 国 名称 我们 in_生活 16:1 16:2 如果我创建一个类来表示我的顶点,我可以查询它们:

公共阶层人士 { 公共字符串名称{get;set;} } 公营国家 { 公共字符串名称{get;set;} } 公车 { 公共字符串名称{get;set;} } //... var结果=db.Select.FromCountry.ToList; 结果中的foreach var项 { Console.WriteLineitem.Name; } 输出:

英国 我们 但是,我希望能够访问顶点之间的连接:

公共阶层人士 { 公共字符串名称{get;set;} 公共国家生活{get;set;} 公共IEnumerable拥有{get;set;} } 公营国家 { 公共字符串名称{get;set;} 公共IEnumerable生命{get;set;} } 公车 { 公共字符串名称{get;set;} 公众拥有{get;set;} } 查询不会填充这些参数。但是,我可以为边添加ORID列表:

公共阶层人士 { 公共字符串名称{get;set;} 公共列表输出{get;set;} public List out_拥有{get;set;} } 公营国家 { 公共字符串名称{get;set;} _{get;set;}中的公共列表 } 公车 { 公共字符串名称{get;set;} _中的公共列表拥有{get;set;} } 如果我只是尝试查询顶点,则此操作无效:

db.Select.FromPerson.ToList; 库的不同部分显然需要不同类型的边缘列表。如果我没记错的话,一部分要求它们是列表,一部分要求它们是哈希集,另一部分要求它们具有无参数构造函数。但如果我专门查询边,它确实有效:

db.SelectName.AsName .也不是“拥有的”。是“拥有的” .也没有“生命”,也没有“生命” .FromPerson.ToList; 不幸的是,ORID类没有我需要的任何信息;这只是一个参考,我可以在其他查询中使用

我的最后一个解决方案是尝试创建垫片属性,该属性将根据RID查询数据库,只是为了看看我是否可以让事情正常进行:

公共阶层人士 { 公共字符串名称{get;set;} public List out_拥有{get;set;} 公共列表输出{get;set;} 公共IEnumerable所有者 { 收到 { 如果拥有!=null&& out\u Owns!=null&&Owns.Count==out\u Owns.Count返回Owns; 拥有=新列表; 如果out_Owns==null | | out_Owns.Count==0返回Owns; 使用ODatabase db=新的ODatabaseCars { owns=db.SelectName.AsName .也说“拥有”,就像你拥有一样 .Fromout_拥有.First.ToList; } 归还所有权; } } 公共国家生活 { 收到 { 如果有生命!=空返回生命; 如果out_lifes==null | | out_lifes.Count==0,则返回null; 使用ODatabase db=新的ODatabaseCars { lives=db.SelectName.AsName .还活着.就像你活着一样 .Fromout_lifes.First.ToList .FirstOrDefault; } } } 私人拥有; 私人乡村生活; } 公营国家 { 公共字符串名称{get;set;} _{get;set;}中的公共列表 公共生活 { 收到 { 如果生存!=null&& in_lifes!=null&&lifes.Count==in_lifes.Count返回生命; 生命=新列表; 如果in_lifes==null | | in_lifes.Count==0返回生命; 使用ODatabase db=新的ODatabaseCars { StringBuilder sb=新的StringBuilder; 每个ORID id在您的生活中 { sb.AppendFormat{0},id; } 如果某人的长度大于0 { b.Removesb.Length-1,1; } lives=db.SelectName.AsName .也不是“拥有的”。是“拥有的” .也没有“生命”,也没有“生命” .Fromstring.Format[{0}],sb.ToList; } 回归生命; } } 私人生活; } 公车 { 公共字符串名称{get;set;} _中的公共列表拥有{get;set;} 公众人士拥有 { 收到 { 如果拥有!=空返回拥有; 如果in_Owns==null | in_Owns.Count==0,则返回null; 使用ODatabase db=新的ODatabaseCars { owns=db.SelectName.AsName .也不是“拥有的”。是“拥有的” .也没有“生命”,也没有“生命” .Fromin_拥有.First.ToList .FirstOrDefault; } } } 私人拥有; } 这个函数很有用,但它看起来像是非常可怕的代码。我在我的get访问器中查询数据库,尽管缓存结果在某种程度上缓解了这个问题,并且这样做需要知道链接顶点的属性,这在编译时是无法捕获的。这些问题只会随着数据库规模的增加而增加,无论是在记录数量上,还是在属性数量上,我们将要迁移的一个MySQL表目前有超过700万行,尽管它可能会被分成几个类,但其中一个MySQL表有超过100列

我希望能够简单地调用db.Select.FromMyVertex.ToList;并获取一个MyVertex对象列表,其中包含图形中从顶点出来的边的属性。这个图书馆能做到这一点吗?这是否适用于任何C库?

将修补程序推送到

你能试试最新的版本吗

看看这个例子

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Orient.Client;

namespace Orient.Tests.Issues
{
    // http://stackoverflow.com/questions/26661636/orientdb-net-binary-for-models

    [TestClass]
    public class StackOverflow_q_26661636
    {
        TestDatabaseContext _context;
        ODatabase _database;

        [TestInitialize]
        public void Init()
        {
            _context = new TestDatabaseContext();
            _database = new ODatabase(TestConnection.GlobalTestDatabaseAlias);

            _database.Create.Class<Person>().Extends<OVertex>().CreateProperties().Run();
            _database.Create.Class<Country>().Extends<OVertex>().CreateProperties().Run();
            _database.Create.Class<Car>().Extends<OVertex>().CreateProperties().Run();
            _database.Create.Class("Owns").Extends<OEdge>().Run();
            _database.Create.Class("Lives").Extends<OEdge>().Run();

        }

        [TestCleanup]
        public void Cleanup()
        {
            _database.Dispose();
            _context.Dispose();
        }

        [TestMethod]
        [TestCategory("Stackoverflow")]
        public void q_26661636()
        {
            var lukaPerson = new Person { Name = "Luca" };
            var lpV = _database.Create.Vertex(lukaPerson).Run();

            var ferrariModenaCar = new Car { Name = "Ferrari Modena" };
            var fmcV = _database.Create.Vertex(ferrariModenaCar).Run();
            var bmwCar = new Car { Name = "BMW" };
            var bmwcV = _database.Create.Vertex(bmwCar).Run();
            var lp_fmcE = _database.Create.Edge("Owns").From(lpV.ORID).To(fmcV.ORID).Run();
            var lp_bmwcE = _database.Create.Edge("Owns").From(lpV.ORID).To(bmwcV.ORID).Run();

            var countryUS = new Country { Name = "US" };
            var uscV = _database.Create.Vertex(countryUS).Run();
            var lp_uscE = _database.Create.Edge("Lives").From(lpV.ORID).To(uscV.ORID).Run();

            var countryUK = new Country { Name = "UK" };
            var ukcV = _database.Create.Vertex(countryUK).Run();

            var pl = _database.Select().From<Person>().ToList<Person>().FirstOrDefault(p => p.Name == lukaPerson.Name);

            Assert.IsNotNull(pl);
            Assert.AreEqual(lukaPerson.Name, pl.Name);
            Assert.AreEqual(1, pl.out_Lives.Count);
            Assert.AreEqual(2, pl.out_Owns.Count);
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public List<ORID> out_Lives { get; set; }
        public List<ORID> out_Owns { get; set; }
    }

    public class Country
    {
        public string Name { get; set; }
        public List<ORID> in_Lives { get; set; }
    }

    public class Car
    {
        public string Name { get; set; }
        public List<ORID> in_Owns { get; set; }
    }
}

所以,正如@Roman所说,graph数据库的设计并不是为了实现我想要的。但是,我开发了一些扩展方法,使用遍历生成结果

作为先决条件,此解决方案中使用的所有模型都需要扩展ABaseModel,与ABaseModel位于同一命名空间中,并且具有无参数构造函数。基类:

使用Orient.Client; 命名空间MyApplication { 公共抽象类ABaseModel { 公共ORID ORID{get;set;} 公共整数覆盖{get;set;} 公共或记录类型OType{get;set;} 公共短OClassId{get;set;} 公共字符串OClassName{get;set;} } } 这只是为扩展方法提供了一个公共基础,并且在使用TypeMapper映射时包含了模型的所有保留属性

完成后,方法遍历此ODatabase、string和遍历此ODatabase、ORID扩展ODatabase以提供所需的功能:

使用Orient.Client; 使用Orient.Client.Mapping; 使用制度; 使用系统集合; 使用System.Collections.Generic; 使用System.Linq; 运用系统反思; 使用System.Text.RegularExpressions; 命名空间MyApplication { /// ///为提供扩展方法 /// 公共静态类数据库扩展 { 私有常量int SINGLE\u RID\u TARGET\u PATTERN\u INDEX=3; 私有静态只读字符串[]legalTargets={ @^?:类别:?[a-zA-Z][a-zA-Z0-9]*$,//类别 @^群集:\d+$,//根群集 @^\[?:\d+:\d+\s*,?\s**?:\d+:\d+\]$,//RID数组 @^\d+:\d+$//单根记录RID }; /// ///使用traverse填写类型为的模型集合。必须打开。 /// /// ///请注意,遍历可能比较慢,选择可能更合适。请参阅 /// http://www.orientechnologies.com/docs/last/orientdb.wiki/SQL-Traverse.htmlshould-i-use-traverse-or-select /// /// 填充模型特性时不遵循轻量边。确保使用重量级的边缘与 ///alter property MyEdgeClass.out MANDATORY=true,alter property MyEdgeClass.in MANDATORY=true,否则 ///使用alter database custom UseLightWeightEdge=false。 /// ///模型类型。必须扩展,有一个无参数构造函数,最重要的是它必须在同一个 ///命名空间为。 ///要查询的数据库 ///要遍历的类、群集、RID列表或RID。RID的形式为clusterId:clusterPosition。列表的格式为 ///具有一个或多个元素的[RID,RID,…]将忽略空白。集群的形式为cluster:clusterName或cluster:clusterId。 ///If是无效的格式 ///类型的模型的可枚举集合。模型的公共实例属性将填充其值 ///基于遍历中的所有非轻量级边。 公共静态IEnumerable遍历此ODatabase数据库,其中的字符串T:ABaseModel,新建 { //目标的健全性检查 布尔匹配=假; legalTargets中的foreach字符串模式 { 如果Regex.IsMatchfrom,则为模式 { 匹配=真; 打破 } } 如果!匹配 { 抛出新ArgumentExceptionReverse目标必须是类、群集、RID列表或单个RID.,来自; } bool fromSingleRecord=Regex.IsMatchfrom,legalTargets[SINGLE_RID_TARGET_PATTERN_INDEX]; //遍历数据库 string sql=string.Formattraverse*from{0},from; 列表结果=db.Querysql; DatabaseTraversal traversal=新建DatabaseTraversaldb,结果; //过程结果 IEnumerable models=traversal.ToModel; 如果来自SingleRecord { //调用了TraverseORID,或者使用RID字符串调用了Traverse的客户端代码-返回单个元素 模型=模型。其中m=>m.ORID.ToString.Equalsfrom; } 收益模型; } /// ///使用导线测量填充类型为的模型。必须是开放的。 /// /// ///请注意,遍历可能比较慢,选择可能更合适。看见 /// http://www.orientechnologies.com/docs/last/orientdb.wiki/SQL-Traverse.htmlshould-i-use-traverse-or-select /// ///填充模型特性时不遵循轻量边。确保使用重量级的边缘与 ///alter property MyEdgeClass.out MANDATORY=true,alter property MyEdgeClass.in MANDATORY=true,否则 ///使用alter database custom UseLightWeightEdge=false。 /// ///模型类型。必须扩展,有一个无参数构造函数,最重要的是它必须在同一个 ///命名空间为。 ///要查询的数据库 ///根需要穿过。 ///表示由指示的记录的模型。 公共静态T遍历此ODatabase数据库,ORID,其中T:ABaseModel,新建 { //Traversefrom.ToString保证有0或1个元素 返回db.Traversefrom.ToString.SingleOrDefault; } /// ///用于遍历的Helper类 /// 私有类数据库遍历 { 私人可数文件; 可数边; 私人词典文献地图; 私有静态只读函数isModelPropertyEnumerableHelper=pType=>typeofSystem.Collections.IEnumerable.IsAssignableFrompType; 私有静态只读函数isModelPropertyHelper=pInfo=> { 字符串别名=pInfo.Name; OProperty propertyAlias=pInfo.GetCustomAttributesTypeOfProperty.Wherettr=>!string.IsNullOrEmptyPropertyAtr.Alias.SingleOrDefault作为OProperty; 如果propertyAlias!=null { 别名=propertyAlias.alias; } 返回别名; }; 私有静态只读操作setPropertieHelper=父级、子级、类名=> { PropertyInfo[]properties=parent.GetType.GetPropertiesBindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.GetProperty; PropertyInfo propertySingle=properties.Whereprop=>IsModelPropertyprop,className.SingleOrDefault; PropertyInfo propertyCollection=properties.Whereprop=>IsModelCollectionPropertyprop,className.SingleOrDefault; 如果propertySingle!=null { propertySingle.SetValueparent,child; } 如果propertyCollection!=null,则为else { dynamic propertyValue=propertyCollection.GetValueparent; 如果propertyValue==null { 类型ListSoft=typeofList.MakeGenericTypepropertyCollection.PropertyType.GenericTypeArguments[0]; IEnumerable collection=IEnumerableActivator.CreateInstancelistOfT; propertyValue=集合; propertyCollection.SetValueparent,集合; } propertyValue.Addchild; } }; /// ///创建新对象。必须是开放的。 /// ///要遍历的数据库。发现边所需。 ///traverse*从$target生成的文档 公共数据库遍历数据库,IEnumerable文档 { 本文件=文件; documentMap=documents.ToDictionarydoc=>doc.ORID; //需要知道documentMap中的哪些RID是边 edges=database.Select.FromE.ToList.wheredge=>documentMap.ContainsKeyedge.ORID; } /// ///填充模型对象 /// ///要返回的模型类型 ///出现在遍历中的模型对象的集合。 公共IEnumerable ToModel,其中T:ABaseModel,纽约 { 如果documents.Count==0,则返回null; IDictionary models=新词典; 每个边缘都有一个e { ODocument outDoc=文档地图[e.OutV]; ODocument inDoc=文档地图[e.InV]; 动态outModel,inModel; bool containsOutId=models.ContainsKeyoutDoc.ORID; bool containsInId=models.ContainsKeyinDoc.ORID; //设置边指向/指向的模型的值 如果含有苏蒂德 { outModel=模型[outDoc.ORID]; } 其他的 { outModel=GetNewPropertyModeltypeofT.Namespace,outDoc.OClassName; MapPropertiesoutDoc,outModel; models.AddoutModel.ORID,outModel; } 如果包含 { inModel=模型[inDoc.ORID]; } 其他的 { inModel=GetNewPropertyModeltypeofT.Namespace,inDoc.OClassName; MapPropertiesinDoc,inModel; models.AddinDoc.ORID,inModel; } //将outModel的属性值设置为inModel(如果存在) setPropertiesHelperoutModel,inModel,e.OClassName; setPropertiesHelperinModel,outModel,e.OClassName; } //T型回归模型 IEnumerable result=models.Selectkvp=>kvp.Value.Wheremodel=>model.OClassName.EqualstypeofT.Name.Cast; 返回结果; } /// ///将顶点的非边特性映射到模型 /// ///模型类型 ///顶点 ///模型对象 私有静态void映射属性文档,T resultObj { TypeMapperBase.GetInstanceForTypeSoft作为TypeMapper.ToObject文档,resultObj; } /// ///创建模型类型的新实例 /// ///模型的名称空间 ///模型的类名 ///类nSpace.modelName的新初始化实例 私有静态动态GetNewPropertyModelstring空间,字符串模型名 { Type modelClass=Type.GetTypestring.Format{0}.{1},nSpace,modelName; 返回modelClass.GetConstructorType.EmptyTypes.Invokenull; } /// ///检查给定属性或其别名是否为顶点的类名且不可枚举 /// ///要比较名称/别名的属性。别名应设置为 ///要比较的顶点类名 ///如果已命名或具有 ///别名为且不是集合类型的属性。 私有静态bool IsModelPropertyPropertyInfo currentProperty,字符串名称 { 字符串别名=IsModelPropertyHelpPerCurrentProperty; return!isModelPropertyEnumerableHelpercurrentProperty.PropertyType&&alias.Equalsname; } /// ///检查给定属性或其别名是否为顶点的c 类名称,并且是可枚举的 /// ///要比较名称/别名的属性。别名应设置为 ///要比较的顶点类名 ///如果已命名或具有 ///属性,别名为,并且是集合类型。 私有静态布尔值IsModelCollectionPropertyPropertyInfo currentProperty,字符串名称 { 字符串别名=IsModelPropertyHelpPerCurrentProperty; 返回isModelPropertyEnumerableHelpercurrentProperty.PropertyType&&alias.Equalsname; } } } } 用法示例:

Person luca=db.Traversenew或12:0; //luca.Name==luca //卢卡,拥有无效的 //luca.Owns.Count==1 //luca.Owns[0]。名称==法拉利摩德纳 //luca.Owns[0]。Owner==luca //卢卡,活着无效的 //luca.lifes.Name==英国 //卢卡·生命·居民!=无效的 //luca.lifes.Residents.Count==2 //luca.Lifes.Residents[0]==luca //luca.Lifes.Residents[1]。Lifes.Residents[0]==luca //luca.lifes.Residents[1]。Owns==null->因为任何汽车都没有优势
官方的OrientDB.NET驱动程序是:我昨天晚些时候确实发现了。这是我链接到的回购协议的一个分支,虽然它比原始协议提前了几次提交,但对于我的用例来说,它的执行是相同的。这似乎解决了需要了解目标模型的详细信息以获得ORID列表的问题,但是,有没有办法用ORID指向的顶点的数据类型填充模型?如果希望所有数据都包含在一个文档中,则需要使用具有嵌入字段类型的文档数据库。在这种情况下,您需要再次使用_database.Load.ORID.RunChecked,如果您通过这种方式查询具有`var pl=_database.Select.From.ToList*:-1.FirstOrDefaultp=>p.ORID==lpV.ORID.to;`记录是预取的,在_database.ClientCache中,您拥有所有记录