コード例 #1
0
ファイル: DbEntry.cs プロジェクト: agmarchuk/AdapterMongo
        private static XElement GetItemByIdFormatted(EntityInfo ent_info, XElement format)
        {
            XElement result = new XElement("record",
                new XAttribute("id", ent_info.LastId),
                ent_info.TypeId == null ? null : new XAttribute("type", ent_info.TypeId), // Сэкономил запрос на тип
                null);

            // Множество точек рассширения дерева
            List<ExtendInfo> extend_points = new List<ExtendInfo>();
            extend_points.Add(new ExtendInfo() { ent = ent_info, format = format, record = result });
            int level = 1; // для эксперимента по ограничению уровня раскрытия

            while (extend_points.Count > 0)
            {
                // Набор всех идентификаторов, по которым надо найти обратные записи
                List<string> forinverse = new List<string>();
                //List<string> forinverse_special = new List<string>(); // for experiment
                List<string> fordirect = new List<string>();
                List<ExtendInfo> extend_points_new = new List<ExtendInfo>();
                // формирование множества идентификаторов обратных типов (null - нужны все типы)
                string[] inverse_types = null;
                var inverse_recs = extend_points
                    .SelectMany(ep => ep.format.Elements("inverse").Elements("record"))
                    .ToArray();
                if (inverse_recs.All(inv => inv.Attribute("type") != null))
                {
                    inverse_types = inverse_recs.Select(inv => inv.Attribute("type").Value)
                        .Distinct()
                        .ToArray();
                }

                foreach (var ep in extend_points)
                {
                    EntityInfo entity = ep.ent;
                    XElement ep_format = ep.format;
                    XElement toinclude = ep.record;
                    // Формирование множества forinverseset
                    if (ep_format.Elements("inverse").Any())
                    {
                        forinverse.Add(ep.ent.LastId);
                    }

                    // Обработаем нужные поля
                    string[] fieldnames = ep_format.Elements("field")
                        .Select(f => f.Attribute("prop").Value)
                        .ToArray();
                    if (entity.RecordElements != null)
                        foreach (PredicateInfo field in entity.RecordElements.Where(pi => !pi.IsObjectProperty))
                        {
                            if (!fieldnames.Contains(field.Predicate)) continue;
                            toinclude.Add(new XElement("field", new XAttribute("prop", field.Predicate),
                                field.Lang == null ? null : new XAttribute(ONames.xmllang, field.Lang),
                                field.Value));
                        }
                    // обработаем нужные прямые ссылки
                    string[] directnames = ep_format.Elements("direct")
                        .Select(f => f.Attribute("prop").Value)
                        .ToArray();
                    if (entity.RecordElements != null)
                        foreach (PredicateInfo field in entity.RecordElements.Where(pi => pi.IsObjectProperty))
                        {
                            if (!directnames.Contains(field.Predicate)) continue;
                            fordirect.Add(field.Value);
                        }
                }
                // Теперь сделаем запрос на записи, список которых сформирован в forinverse
                string[] inv_set = forinverse.Distinct().ToArray();
                var query = DbRecords.AsQueryable<EntityInfo>()
                        .Where(r => r.ExternalLinks.ContainsAny(inv_set)).Where(r => !r.IsRemoved);
                if (inverse_types != null) query = query
                    .Where(r => r.TypeId == null || inverse_types.Contains(r.TypeId));
                EntityInfo[] inv_entities = inv_set.Length == 0 ? new EntityInfo[0] :
                    query.ToArray();

                // Теперь сделаем запрос на записи, список которых сформирован в fordirect
                string[] dir_set = fordirect.Distinct().ToArray();
                EntityInfo[] dir_entities = dir_set.Length == 0 ? new EntityInfo[0] :
                    DbRecords.AsQueryable<EntityInfo>()
                        .Where(r => dir_set.Contains(r.LastId)).Where(r => !r.IsRemoved)
                        .ToArray();
                // Теперь надо проанализировать каждую из точек рассширения
                foreach (var ep in extend_points)
                {
                    string id = ep.ent.LastId;
                    // Анализ обратных отношений
                    foreach (XElement f_inverse in ep.format.Elements("inverse"))
                    {
                        string prop = f_inverse.Attribute("prop").Value;
                        //var inv_props = inv_entities
                        //    .SelectMany(en => en.RecordElements.Select(re => new { ent = en, ele = re }))
                        //    .Where(pair => pair.ele.IsObjectProperty &&
                        //        pair.ele.Predicate == prop &&
                        //        pair.ele.Value == id);
                        // Думаю, двойной цикл будет эффективнее
                        foreach (var en in inv_entities)
                        {
                            foreach (var pr in en.RecordElements)
                            {   // проверяем на вид свойства, его имя и то, что ссылка на нужный объект
                                if (pr.IsObjectProperty &&
                                    pr.Predicate == prop &&
                                    pr.Value == id)
                                {
                                    // Опеределяем тип удаленной записи
                                    string inv_t_id = en.TypeId;
                                    // Определяем нужный подформат
                                    XElement f_innerrecord = f_inverse.Elements("record")
                                        .FirstOrDefault(r =>
                                        {
                                            var t_att = r.Attribute("type");
                                            return t_att == null || t_att.Value == inv_t_id; // Здесь надо использовать иерархию типов
                                        });
                                    if (f_innerrecord != null)
                                    {
                                        XElement innerrecord =
                                            new XElement("record",
                                                new XAttribute("id", en.LastId),
                                                new XAttribute("type", inv_t_id));
                                        ep.record.Add(new XElement("inverse",
                                            new XAttribute("prop", prop),
                                            innerrecord));
                                        ExtendInfo inner_ei = new ExtendInfo()
                                        {
                                            ent = en,
                                            format = f_innerrecord,
                                            record = innerrecord
                                        };
                                        extend_points_new.Add(inner_ei);
                                    }
                                }

                            }
                            //XElement innerXrecord = new XElement("record", new XAttribute(
                            //ep.record.Add(new XElement("inverse", new X
                        }

                    }
                    // Анализ формата прямых ссылок
                    foreach (XElement f_direct in ep.format.Elements("direct"))
                    {
                        string prop = f_direct.Attribute("prop").Value;
                        PredicateInfo pi = ep.ent.RecordElements
                            .FirstOrDefault(re => re.IsObjectProperty &&
                                re.Predicate == prop);
                        if (pi == null) continue;
                        // Возможно, надо ставнивать не с LastId, а со всеми слитыми
                        EntityInfo en_direct = dir_entities.FirstOrDefault(de => de.LastId == pi.Value);
                        if (en_direct == null) continue;
                        XElement f_innerrecord = f_direct.Elements("record")
                            .FirstOrDefault(r =>
                            {
                                var t_att = r.Attribute("type");
                                return t_att == null || t_att.Value == en_direct.TypeId; // Здесь надо использовать иерархию типов
                            });
                        if (f_innerrecord == null) continue;
                        XElement innerRecord = new XElement("record",
                            new XAttribute("id", en_direct.LastId),
                            new XAttribute("type", en_direct.TypeId == null ? "" : en_direct.TypeId));
                        ep.record.Add(new XElement("direct", new XAttribute("prop", prop),
                            innerRecord));
                        extend_points_new.Add(new ExtendInfo()
                        {
                            ent = en_direct,
                            format = f_innerrecord,
                            record = innerRecord
                        });
                    }
                }
                extend_points = extend_points_new;
                //extend_points = level > 2 ? new List<ExtendInfo>() : extend_points_new;
                level++;
            }
            return result;
        }
コード例 #2
0
ファイル: DbEntry.cs プロジェクト: agmarchuk/AdapterMongo
        public void IncludeXElement(XElement el)
        {
            DateTime modificationTime_new = DateTime.MinValue;
            XAttribute mt = el.Attribute(ONames.AttModificationTime);
            if (mt != null) DateTime.TryParse(mt.Value, out modificationTime_new);
            modificationTime_new = modificationTime_new.ToUniversalTime();
            string id = el.Attribute(sema2012m.ONames.rdfabout).Value;
            sema2012m.ResInfo ri = table_ri[id];
            string[] link_arr = el.Elements()
                .Select(p => p.Attribute(sema2012m.ONames.rdfresource))
                .Where(res_att => res_att != null)
                .Select(res_att =>
                { // идентификатор берется или из table_ri или оригинальный
                    var v = res_att.Value;
                    sema2012m.ResInfo r;
                    if (!table_ri.TryGetValue(v, out r)) return v;
                    return r.id;
                })
                .ToArray();

            PredicateInfo[] recordElements = el.Elements()
                .Select(pred =>
                {
                    var resource_att = pred.Attribute(sema2012m.ONames.rdfresource);
                    if (resource_att == null)
                    {
                        var lang_att = pred.Attribute(sema2012m.ONames.xmllang);
                        return new PredicateInfo()
                        {
                            IsObjectProperty = false,
                            Predicate = pred.Name.NamespaceName + pred.Name.LocalName,
                            Value = pred.Value,
                            Lang = lang_att == null ? null : lang_att.Value
                        };
                    }
                    else
                    {
                        sema2012m.ResInfo r;
                        string res_id = resource_att.Value;
                        if (table_ri.TryGetValue(res_id, out r)) res_id = r.id;

                        return new PredicateInfo()
                        {
                            IsObjectProperty = true,
                            Predicate = pred.Name.NamespaceName + pred.Name.LocalName,
                            Value = res_id
                        };
                    }
                }).ToArray();
            string[] firstWords = el.Elements(ONames.xNameDatatypeProperty)
                .Select(nm =>
                {
                    string name = nm.Value;
                    if (string.IsNullOrEmpty(name)) return "";
                    string[] parts = name.Split(' ', ',');
                    return parts[0].ToLower();
                }).ToArray();
            //string[] externalLinks = el.Elements()
            string[] externalLinks = recordElements
            .Where(re => re.IsObjectProperty)
            .Select(re => re.Value)
            .ToArray();
            EntityInfo ei = new EntityInfo()
            {
                TypeId = el.Name.NamespaceName + el.Name.LocalName,
                LastId = id, // вычислен
                MergedIds = ri.merged_ids.ToArray(), // вычислен
                IsRemoved = ri.removed, // вычислен
                RecordElements = recordElements,
                FirstWords = firstWords,
                ExternalLinks = externalLinks,
                TimeStamp = modificationTime_new
            };
            buff.Add(ei);
        }
コード例 #3
0
ファイル: DbEntry.cs プロジェクト: agmarchuk/AdapterMongo
 private static IEnumerable<EntityInfo> GetInverseRecordsById(EntityInfo en)
 {
     var entities = DbRecords.AsQueryable<EntityInfo>()
         .Where(r => r.ExternalLinks.Contains(en.LastId));
     return entities;
 }
コード例 #4
0
ファイル: DbEntry.cs プロジェクト: agmarchuk/AdapterMongo
        public static void LoadXFlow(IEnumerable<XElement> xflow)
        {
            foreach (XElement el in xflow)
            {
                if (el.Name == sema2012m.ONames.TagDelete)
                {
                    string delete_id = el.Attribute(sema2012m.ONames.AttItem_id).Value;
                    // Поиск записи для delete_id
                    EntityInfo delete_en = _records.AsQueryable<EntityInfo>()
                        .FirstOrDefault(en => en.MergedIds.Contains(delete_id));
                    if (delete_en == null)
                    {
                        // Завести новую запись
                        delete_en = new EntityInfo()
                        {
                            LastId = delete_id, // на всякий случай...
                            IsRemoved = true,
                            MergedIds = new string[] { delete_id }
                        };
                        _records.Insert(delete_en);
                    }
                    else
                    {
                        // добавим в MergedIds
                        //delete_en.MergedIds = delete_en.MergedIds
                        //    .Concat(new string[] { delete_id }).ToArray();
                        if (!delete_en.IsRemoved) // если уже уничтожен, то ничего делать не надо
                        {
                            delete_en.IsRemoved = true;
                            delete_en.RecordElements = null;
                            delete_en.ExternalLinks = null;
                            // Надо еще вставить проверку того, что уничтожается оригинал записи
                            _records.Save(delete_en);
                        }
                    }
                }
                else if (el.Name == sema2012m.ONames.TagSubstitute)
                {
                    // Поиск записей для old_id и new_id
                    string old_id = el.Attribute(sema2012m.ONames.AttOld_id).Value;
                    EntityInfo old_en = _records.AsQueryable<EntityInfo>()
                        .FirstOrDefault(en => en.MergedIds.Contains(old_id));
                    string new_id = el.Attribute(sema2012m.ONames.AttNew_id).Value;
                    EntityInfo new_en = _records.AsQueryable<EntityInfo>()
                        .FirstOrDefault(en => en.MergedIds.Contains(new_id));
                    // Предыдущие два запроса можно объединить в один, только тогда придется разбираться что есть что
                    if (old_en == null && new_en == null)
                    { // Вообще нет записей
                        // заводим одну с общим списком слитых идентификаторов, оригиналом определяем новый идентификатор
                        EntityInfo en = new EntityInfo()
                        {
                            MergedIds = new string[] { old_id, new_id },
                            LastId = new_id
                        };
                        _records.Insert(en);
                    }
                    else if (old_en == null || new_en == null)
                    { // Есть какая-то одна
                        // добавляем в нее другой идентификатор и, в случае, если отсутствует новый, LastId определяем как новый идентификатор
                        EntityInfo en = old_en == null ? new_en : old_en;
                        en.MergedIds = en.MergedIds.Concat(new string[] {
                            old_en == null ? old_id : new_id}).ToArray();
                        if (old_en != null)
                        {
                            // надо скорректировать обратные ссылки на эту сущность
                            string corrected_id = en.LastId;
                            CorrectExternalLinks(corrected_id, new_id);
                            // а теперь заменить на новую
                            en.LastId = new_id;
                        }
                        _records.Save(en);
                    }
                    else if (old_en.Id == new_en.Id)
                    { // Есть обе записи, но они совпадают - слитие произведено, ничего не делаем
                    }
                    else
                    { // Есть две записи и они не совпадают
                        // в новую добавляем в merged старый идентификатор, старую уничтожаем
                        new_en.MergedIds = new_en.MergedIds.Concat(old_en.MergedIds).Distinct().ToArray();
                        // кроме того, если старая уничтожена, то транслируем это в новую (Это не очевидно...)
                        //if (old_en.IsRemoved) new_en.IsRemoved = true;
                        _records.Save(new_en);
                        CorrectExternalLinks(old_en.LastId, new_en.LastId);
                        var query = Query.EQ("_id", old_en.Id);
                        _records.Remove(query);
                    }
                }
                else
                { // это запись
                    var aboutatt = el.Attribute(sema2012m.ONames.rdfabout);
                    if (aboutatt == null) continue;
                    string id = aboutatt.Value;
                    // Выявляем временную отметку
                    DateTime modificationTime_new = DateTime.MinValue;
                    XAttribute mt = el.Attribute(sema2012m.ONames.AttModificationTime);
                    if (mt != null) DateTime.TryParse(mt.Value, out modificationTime_new);
                    modificationTime_new = modificationTime_new.ToUniversalTime();

                    // Проверка на наличие мзаписи с таким же идентификатором
                    EntityInfo existant_en = _records.AsQueryable<EntityInfo>()
                        .FirstOrDefault(en => en.MergedIds.Contains(id));
                    if (existant_en != null && existant_en.TypeId != null &&
                         (existant_en.LastId != id || (existant_en.LastId == id && existant_en.TimeStamp > modificationTime_new))
                        )
                    { // Есть полная мзапись и она лучше, чем пришедшая
                        // Ничего делать не надо
                    }
                    else
                    { // Есть еще два варианта, в обоих придется создавать новую мзапись и уничтожать старую, надо следить за LastIs и MergedIds
                        // Устанавливаем дефолтные значения: массива слитых идентификаторов, последнего идентификатора и признака IsRemoved
                        string[] merged_arr = new string[] { id }; // Это для случая, когда нет мзаписи
                        string lid = id; // Это для случая, когда нет мзаписи
                        bool ir = false; // Это для случая, когда нет мзаписи
                        if (existant_en != null)
                        { // мзапись есть, но она неполная или хуже пришедшей записи
                            merged_arr = existant_en.MergedIds;
                            lid = existant_en.LastId;
                            ir = existant_en.IsRemoved;
                            // саму запись уничтожить
                            var query = Query.EQ("_id", existant_en.Id);
                            _records.Remove(query);
                            // LastId-идентификатция не меняется НЕ надо корректировать обратные ссылки
                        }
                        else
                        { // LastId совпадает с id - не надо корректировать обратные ссылки
                        }
                        // Штатный случай: новая запись, но с накопленным массивом слитых
                        // Запросим текущие LastId объектных ссылок
                        string[] link_arr = el.Elements().Select(p => p.Attribute(ONames.rdfresource))
                            .Where(res_att => res_att != null).Select(res_att => res_att.Value).ToArray();
                        var ext_ents = _records.AsQueryable<EntityInfo>()
                            .Where(en => en.MergedIds.ContainsAny(link_arr))
                            .Select(en => new { last = en.LastId, merged = en.MergedIds })
                            .ToArray();

                        PredicateInfo[] recordElements = el.Elements()
                            .Select(pred =>
                            {
                                var resource_att = pred.Attribute(sema2012m.ONames.rdfresource);
                                if (resource_att == null)
                                {
                                    var lang_att = pred.Attribute(sema2012m.ONames.xmllang);
                                    return new PredicateInfo()
                                    {
                                        IsObjectProperty = false,
                                        Predicate = pred.Name.NamespaceName + pred.Name.LocalName,
                                        Value = pred.Value,
                                        Lang = lang_att == null ? null : lang_att.Value
                                    };
                                }
                                else
                                {
                                    var candidate = ext_ents.FirstOrDefault(en => en.merged.Contains(resource_att.Value));
                                    string corrected_resource = candidate == null ?
                                        resource_att.Value :
                                        candidate.last;
                                    return new PredicateInfo()
                                    {
                                        IsObjectProperty = true,
                                        Predicate = pred.Name.NamespaceName + pred.Name.LocalName,
                                        Value = corrected_resource,
                                    };
                                }
                            }).ToArray();
                        string[] firstWords = el.Elements(ONames.xNameDatatypeProperty)
                            .Select(nm =>
                            {
                                string name = nm.Value;
                                if (string.IsNullOrEmpty(name)) return "";
                                string[] parts = name.Split(' ', ',');
                                return parts[0].ToLower();
                            }).ToArray();
                        //string[] externalLinks = el.Elements()
                        //    .Where(pred => pred.Attribute(ONames.rdfresource) != null)
                        //    .Select(pred => pred.Attribute(ONames.rdfresource).Value)
                        //    .ToArray();
                        string[] externalLinks = recordElements
                            .Where(re => re.IsObjectProperty)
                            .Select(re => re.Value)
                            .ToArray();
                        EntityInfo ei = new EntityInfo()
                        {
                            TypeId = el.Name.NamespaceName + el.Name.LocalName,
                            LastId = lid, // вычислен
                            MergedIds = merged_arr, // вычислен
                            IsRemoved = ir, // вычислен
                            RecordElements = recordElements,
                            FirstWords = firstWords,
                            ExternalLinks = externalLinks,
                            TimeStamp = modificationTime_new
                        };
                        _records.Insert<EntityInfo>(ei);
                    }
                }
            }
        }