예제 #1
0
        /// <summary>
        /// 查找所有引用指定模型标识的EntityRef Member集合
        /// </summary>
        public List <EntityRefModel> FindEntityRefModels(ulong targetEntityModelID)
        {
            var rs = new List <EntityRefModel>();

            ModelNode[] ls = FindNodesByType(ModelType.Entity);
            for (int i = 0; i < ls.Length; i++)
            {
                EntityModel model = (EntityModel)ls[i].Model;
                //注意:不能排除自身引用,主要指树状结构的实体
                for (int j = 0; j < model.Members.Count; j++)
                {
                    if (model.Members[j].Type == EntityMemberType.EntityRef)
                    {
                        EntityRefModel refMember = (EntityRefModel)model.Members[j];
                        //注意不排除聚合引用
                        for (int k = 0; k < refMember.RefModelIds.Count; k++)
                        {
                            if (refMember.RefModelIds[k] == targetEntityModelID)
                            {
                                rs.Add(refMember);
                            }
                        }
                    }
                }
            }
            return(rs);
        }
예제 #2
0
        /// <summary>
        /// 增减外键引用计数值
        /// </summary>
        internal async ValueTask AddEntityRefAsync(EntityRefModel entityRef,
                                                   ApplicationModel fromApp, Entity fromEntity, int diff)
        {
            Debug.Assert(diff != 0);
            Debug.Assert(fromEntity.Id.RaftGroupId != 0);

            var targetId = fromEntity.GetEntityId(entityRef.FKMemberIds[0]);

            if (targetId == null || targetId.IsEmpty)
            {
                return;
            }
            ulong targetModelId = entityRef.IsAggregationRef ? fromEntity.GetUInt64(entityRef.TypeMemberId) : entityRef.RefModelIds[0];
            var   targetModel   = await RuntimeContext.Current.GetModelAsync <EntityModel>(targetModelId);

            var targetAppId = IdUtil.GetAppIdFromModelId(targetModelId);
            var targetApp   = await RuntimeContext.Current.GetApplicationModelAsync(targetAppId);

            //注意编码
            uint fromTableId = KeyUtil.EncodeTableId(fromApp.StoreId, entityRef.Owner.TableId);

            var item = new RefFromItem()
            {
                TargetEntityId  = targetId,
                FromTableId     = fromTableId,
                FromRaftGroupId = fromEntity.Id.RaftGroupId
            };

            lock (this)
            {
                if (refs == null)
                {
                    item.Diff = diff;
                    refs      = new List <RefFromItem> {
                        item
                    };
                }
                else
                {
                    for (int i = 0; i < refs.Count; i++)
                    {
                        if (refs[i].TargetEntityId == targetId && refs[i].FromRaftGroupId == fromEntity.Id.RaftGroupId)
                        {
                            item.Diff = refs[i].Diff + diff;
                            refs[i]   = item;
                            return;
                        }
                    }

                    //未找到
                    item.Diff = diff;
                    refs.Add(item);
                }
            }
        }
예제 #3
0
        private static void GetEntityMemberTypeStringAndReadOnly(EntityMemberModel mm,
                                                                 ref string typeString, ref bool readOnly, DesignTree designTree)
        {
            switch (mm.Type)
            {
            case EntityMemberType.DataField:
                //判断是否是枚举
                DataFieldModel dmm = mm as DataFieldModel;
                //if (dmm.DataType == EntityFieldType.Enum)
                //{
                //    if (string.IsNullOrEmpty(dmm.EnumModelID))
                //        typeString = "int";
                //    else
                //    {
                //        string[] sr = dmm.EnumModelID.Split('.');
                //        typeString = sr[0] + ".Enums." + sr[1];
                //    }
                //}
                if (dmm.DataType == EntityFieldType.EntityId)
                {
                    typeString = "EntityId";
                }
                else
                {
                    typeString = dmm.DataType.GetValueType().FullName;     //TODO:简化类型名称
                }

                //系统存储分区键与sql存储的主键为只读
                readOnly |= dmm.IsPartitionKey || dmm.IsPrimaryKey;

                if (dmm.AllowNull && (dmm.DataType != EntityFieldType.String &&
                                      dmm.DataType != EntityFieldType.EntityId &&
                                      dmm.DataType != EntityFieldType.Binary && typeString != "object"))
                {
                    typeString += "?";
                }
                break;

            case EntityMemberType.EntityRef:
                EntityRefModel rm = (EntityRefModel)mm;
                if (rm.IsAggregationRef)
                {
                    typeString = TypeHelper.Type_EntityBase;
                }
                else
                {
                    if (rm.RefModelIds.Count == 0)     //Todo:待移除,因误删除模型引用项导致异常
                    {
                        typeString = TypeHelper.Type_EntityBase;
                    }
                    else
                    {
                        var targetModelNode = designTree.FindModelNode(ModelType.Entity, rm.RefModelIds[0]);
                        typeString = $"{targetModelNode.AppNode.Model.Name}.Entities.{targetModelNode.Model.Name}";
                    }
                }
                break;

            case EntityMemberType.EntitySet:
            {
                EntitySetModel sm = (EntitySetModel)mm;
                var            targetModelNode = designTree.FindModelNode(ModelType.Entity, sm.RefModelId);
                typeString = $"EntityList<{targetModelNode.AppNode.Model.Name}.Entities.{targetModelNode.Model.Name}>";
                readOnly   = true;
            }
            break;

            case EntityMemberType.AggregationRefField:
                typeString = "object";
                readOnly   = true;
                break;

            //case EntityMemberType.Formula:
            //case EntityMemberType.Aggregate:
            //FormulaModel fmm = mm as FormulaModel;
            //typeString = TypeService.GetEntityFieldValueType(fmm.DataType).FullName;
            //readOnly = true;
            //break;
            case EntityMemberType.Tracker:
                throw ExceptionHelper.NotImplemented();

            //GetEntityMemberTypeStringAndReadOnly(
            //    (mm as TrackerModel).TargetMember, ref typeString, ref readOnly);
            //readOnly = true;
            //break;
            case EntityMemberType.AutoNumber:
                typeString = "string";
                readOnly   = true;
                break;

            //case EntityMemberType.ImageRef:
            //typeString = TypeHelper.Type_IImageSource;
            //readOnly = false;
            //break;
            default:
                typeString = "object";
                break;
            }
        }
예제 #4
0
        static TestHelper()
        {
            SysAppModel = new ApplicationModel("appbox", Consts.SYS, Consts.SYS_APP_ID);

            AdminPermissionModel     = new PermissionModel(Consts.SYS_PERMISSION_ADMIN_ID, "Admin");
            DeveloperPermissionModel = new PermissionModel(Consts.SYS_PERMISSION_DEVELOPER_ID, "Developer");

            OrderStatusModel = new EnumModel(SYS_ENUM_MODEL_ID | (1 << IdUtil.MODELID_SEQ_OFFSET), "OrderStatus");
            OrderStatusModel.Items.Add(new EnumModelItem("New", 0));
            OrderStatusModel.Items.Add(new EnumModelItem("Paid", 1));

            EmploeeModel = new EntityModel(Consts.SYS_EMPLOEE_MODEL_ID, Consts.EMPLOEE, EntityStoreType.StoreWithMvcc);
            var name = new DataFieldModel(EmploeeModel, Consts.NAME, EntityFieldType.String);

            EmploeeModel.AddSysMember(name, Consts.EMPLOEE_NAME_ID);
            var account = new DataFieldModel(EmploeeModel, Consts.ACCOUNT, EntityFieldType.String);

            account.AllowNull = true;
            EmploeeModel.AddSysMember(account, Consts.EMPLOEE_ACCOUNT_ID);
            var password = new DataFieldModel(EmploeeModel, Consts.PASSWORD, EntityFieldType.Binary);

            password.AllowNull = true;
            EmploeeModel.AddSysMember(password, Consts.EMPLOEE_PASSWORD_ID);

            //Add indexes
            var ui_account_pass = new EntityIndexModel(EmploeeModel, "UI_Account_Password", true,
                                                       new FieldWithOrder[] { new FieldWithOrder(Consts.EMPLOEE_ACCOUNT_ID) },
                                                       new ushort[] { Consts.EMPLOEE_PASSWORD_ID });

            EmploeeModel.SysStoreOptions.AddSysIndex(EmploeeModel, ui_account_pass, Consts.EMPLOEE_UI_ACCOUNT_ID);

            //测试用分区表
            VehicleStateModel = new EntityModel(((ulong)Consts.SYS_APP_ID << 32) | 18, "VehicleState", EntityStoreType.StoreWithMvcc);
            var vid = new DataFieldModel(VehicleStateModel, "VehicleId", EntityFieldType.Int32);

            VehicleStateModel.AddMember(vid);
            var lng = new DataFieldModel(VehicleStateModel, "Lng", EntityFieldType.Float);

            VehicleStateModel.AddMember(lng);
            var lat = new DataFieldModel(VehicleStateModel, "Lat", EntityFieldType.Float);

            VehicleStateModel.AddMember(lat);
            var pks = new PartitionKey[1];

            pks[0] = new PartitionKey()
            {
                MemberId = vid.MemberId, OrderByDesc = false
            };
            VehicleStateModel.SysStoreOptions.SetPartitionKeys(VehicleStateModel, pks);

            //测试树状结构
            ulong orgUnitModelId = ((ulong)Consts.SYS_APP_ID << 32) | 19;

            OrgUnitModel = new EntityModel(orgUnitModelId, "OrgUnit", EntityStoreType.StoreWithMvcc);
            var ouName = new DataFieldModel(OrgUnitModel, "Name", EntityFieldType.String);

            OrgUnitModel.AddSysMember(ouName, 1 << IdUtil.MEMBERID_SEQ_OFFSET);
            var parentId = new DataFieldModel(OrgUnitModel, "ParentId", EntityFieldType.EntityId, true);

            parentId.AllowNull = true;
            OrgUnitModel.AddSysMember(parentId, 2 << IdUtil.MEMBERID_SEQ_OFFSET);
            var parent = new EntityRefModel(OrgUnitModel, "Parent", orgUnitModelId, new ushort[] { parentId.MemberId });

            parent.AllowNull = true;
            OrgUnitModel.AddSysMember(parent, 3 << IdUtil.MEMBERID_SEQ_OFFSET);
            var childs = new EntitySetModel(OrgUnitModel, "Childs", orgUnitModelId, parent.MemberId);

            OrgUnitModel.AddSysMember(childs, 4 << IdUtil.MEMBERID_SEQ_OFFSET);

            //----以下测试映射至SqlStore的实体---
            SqlStoreModel = new DataStoreModel(DataStoreKind.Sql, "appbox.Store.PostgreSQL;appbox.Store.PgSqlStore", "DemoDB");

            ulong cityModelId = ((ulong)Consts.SYS_APP_ID << 32) | 25;

            CityModel = new EntityModel(cityModelId, "City", new SqlStoreOptions(SqlStoreModel.Id));
            var cityCode = new DataFieldModel(CityModel, "Code", EntityFieldType.Int32);

            CityModel.AddMember(cityCode);
            var cityName = new DataFieldModel(CityModel, "Name", EntityFieldType.String);

            CityModel.AddMember(cityName);
            var cityPerson = new DataFieldModel(CityModel, "Persons", EntityFieldType.Int32);

            CityModel.AddMember(cityPerson);
            var cityPk = new List <FieldWithOrder>();

            cityPk.Add(new FieldWithOrder {
                MemberId = cityCode.MemberId, OrderByDesc = false
            });
            CityModel.SqlStoreOptions.SetPrimaryKeys(CityModel, cityPk);

            ulong customerModelId = ((ulong)Consts.SYS_APP_ID << 32) | 26;

            CustomerModel = new EntityModel(customerModelId, "Customer", new SqlStoreOptions(SqlStoreModel.Id));
            var customerId = new DataFieldModel(CustomerModel, "Id", EntityFieldType.Int32);

            CustomerModel.AddMember(customerId);
            var customerName = new DataFieldModel(CustomerModel, "Name", EntityFieldType.String);

            CustomerModel.AddMember(customerName);
            var customerCityId = new DataFieldModel(CustomerModel, "CityId", EntityFieldType.Int32, true);

            CustomerModel.AddMember(customerCityId);
            var customerCity = new EntityRefModel(CustomerModel, "City", cityModelId, new ushort[] { customerCityId.MemberId });

            CustomerModel.AddMember(customerCity);
            var customerPk = new List <FieldWithOrder>();

            customerPk.Add(new FieldWithOrder {
                MemberId = customerId.MemberId, OrderByDesc = false
            });
            CustomerModel.SqlStoreOptions.SetPrimaryKeys(CustomerModel, customerPk);

            ulong orderModelId = ((ulong)Consts.SYS_APP_ID << 32) | 27;

            OrderModel = new EntityModel(orderModelId, "Order", new SqlStoreOptions(SqlStoreModel.Id));
            var orderId = new DataFieldModel(OrderModel, "Id", EntityFieldType.Int32);

            OrderModel.AddMember(orderId);
            var orderCustomerId = new DataFieldModel(OrderModel, "CustomerId", EntityFieldType.Int32, true);

            OrderModel.AddMember(orderCustomerId);
            var orderCustomer = new EntityRefModel(OrderModel, "Customer", customerModelId, new ushort[] { orderCustomerId.MemberId });

            OrderModel.AddMember(orderCustomer);
            var orderPk = new List <FieldWithOrder>();

            orderPk.Add(new FieldWithOrder {
                MemberId = orderId.MemberId, OrderByDesc = false
            });
            OrderModel.SqlStoreOptions.SetPrimaryKeys(OrderModel, orderPk);
        }
예제 #5
0
        /// <summary>
        /// 返回树状结构的实体集合
        /// </summary>
        /// <param name="childrenMember">例:q.T["SubItems"]</param>
        /// <returns></returns>
        public async Task <EntityList> ToTreeListAsync(MemberExpression childrenMember)
        {
            //TODO:目前实现仅支持单一主键且为Guid的树状结构
            Debug.Assert(ReferenceEquals(childrenMember.Owner, T));
            var         children = (EntitySetExpression)childrenMember;
            EntityModel model    = await RuntimeContext.Current.GetModelAsync <EntityModel>(T.ModelID);

            EntitySetModel childrenModel = (EntitySetModel)model.GetMember(children.Name, true);
            EntityRefModel parentModel   = (EntityRefModel)model.GetMember(childrenModel.RefMemberId, true);
            DataFieldModel parentIdModel = (DataFieldModel)model.GetMember(parentModel.FKMemberIds[0], true);

            TreeParentIDMember = (FieldExpression)T[parentIdModel.Name];
            var pk = model.SqlStoreOptions.PrimaryKeys[0].MemberId;

            AddAllSelects(this, model, T, null);

            //TODO:加入自动排序
            //if (!string.IsNullOrEmpty(setmodel.RefRowNumberMemberName))
            //{
            //    SqlSortItem sort = new SqlSortItem(T[setmodel.RefRowNumberMemberName], SortType.ASC);
            //    SortItems.Insert(0, sort);
            //}

            //如果没有设置任何条件,则设置默认条件为查询根级开始
            if (Equals(null, Filter))
            {
                Filter = TreeParentIDMember == null;
            }

            Purpose = QueryPurpose.ToEntityTreeList;
            EntityList list = new EntityList(childrenModel);
            var        db   = SqlStore.Get(model.SqlStoreOptions.StoreModelId);
            var        dic  = new Dictionary <Guid, Entity>(); //TODO: fix pk

            using var cmd  = db.BuildQuery(this);
            using var conn = db.MakeConnection();
            await conn.OpenAsync();

            cmd.Connection = conn;
            Log.Debug(cmd.CommandText);

            using var reader = await cmd.ExecuteReaderAsync();

            while (await reader.ReadAsync())
            {
                Entity obj = FillEntity(model, reader);
                //设置obj本身的EntitySet成员为已加载,防止从数据库中再次加载
                obj.InitEntitySetForLoad(childrenModel);

                var parentId = obj.GetGuidNullable(parentIdModel.MemberId);
                if (parentId.HasValue && dic.TryGetValue(parentId.Value, out Entity parent))
                {
                    parent.GetEntitySet(childrenModel.MemberId).Add(obj);
                }
                else
                {
                    list.Add(obj);
                }

                dic.Add(obj.GetGuid(pk), obj);
            }
            return(list);
        }
예제 #6
0
        /// <summary>
        /// 加载全表为树形结构
        /// </summary>
        public async ValueTask <EntityList> ToTreeListAsync(ushort setMemberId) //TODO:入参排序表达式
        {
            filter = null;                                                      //TODO:暂忽略过滤器
            var model = await RuntimeContext.Current.GetModelAsync <EntityModel>(modelId);

            if (model == null)
            {
                throw new Exception($"EntityModel[{modelId}] not exists.");
            }
            if (!(model.GetMember(setMemberId, true) is EntitySetModel setModel))
            {
                throw new ArgumentException("Must assign EntitySet member id", nameof(setMemberId));
            }
            if (setModel.RefModelId != model.Id)
            {
                throw new ArgumentException("Can't be a tree");
            }
            EntityRefModel refModel = (EntityRefModel)setModel.Owner.GetMember(setModel.RefMemberId, true);

            var list = await ToListAsync();

            if (list == null)
            {
                return(null);
            }

            //TODO:暂简单实现,待优化为排序后处理
            //var sortedList = list.OrderBy(t => t.GetEntityId(setModel.RefMemberId) ?? Guid.Empty); //TODO:check order
            //Dictionary<Guid, Entity> dic = new Dictionary<Guid, Entity>();
            var res = new EntityList(setModel);

            foreach (var obj in list /*sortedList*/)
            {
                //根据上级标识依次加入
                var parentId = obj.GetEntityId(refModel.FKMemberIds[0]);
                if (parentId == null)
                {
                    res.Add(obj);
                }
                else
                {
                    var parent = list.SingleOrDefault(t => (Guid)t.Id == (Guid)parentId);
                    if (parent != null)
                    {
                        parent.InitEntitySetForLoad(setModel); //先尝初始化EntitySet为已加载状态
                        parent.GetEntitySet(setMemberId).Add(obj);
                    }
                    else
                    {
                        res.Add(obj);
                    }
                    //if (dic.TryGetValue(parentId, out Entity parent))
                    //    parent.GetEntitySet(setMemberId).Add(obj);
                    //else
                    //res.Add(obj);
                }

                //dic.Add(obj.Id, obj);
            }
            return(res);
        }
예제 #7
0
        protected override IList <DbCommand> MakeAlterTable(EntityModel model, Design.IDesignContext ctx)
        {
            //TODO:***处理主键变更

            var tableName = model.GetSqlTableName(false, ctx);

            StringBuilder    sb;
            bool             needCommand = false;               //用于判断是否需要处理NpgsqlCommand
            List <string>    fks         = new List <string>(); //引用外键列表
            List <DbCommand> commands    = new List <DbCommand>();

            //List<DbCommand> funcCmds = new List<DbCommand>();
            //先处理表名称有没有变更,后续全部使用新名称
            if (model.IsNameChanged)
            {
                var oldTableName   = model.GetSqlTableName(true, ctx);
                var renameTableCmd = new NpgsqlCommand($"ALTER TABLE \"{oldTableName}\" RENAME TO \"{tableName}\"");
                commands.Add(renameTableCmd);
            }

            //处理删除的成员
            var deletedMembers = model.Members.Where(t => t.PersistentState == PersistentState.Deleted).ToArray();

            if (deletedMembers != null && deletedMembers.Length > 0)
            {
                #region ----删除的成员----
                sb = StringBuilderCache.Acquire();
                foreach (var m in deletedMembers)
                {
                    if (m.Type == EntityMemberType.DataField)
                    {
                        needCommand = true;
                        sb.AppendFormat("ALTER TABLE \"{0}\" DROP COLUMN \"{1}\";", tableName, ((DataFieldModel)m).SqlColOriginalName);
                    }
                    else if (m.Type == EntityMemberType.EntityRef)
                    {
                        EntityRefModel rm = (EntityRefModel)m;
                        if (!rm.IsAggregationRef)
                        {
                            var fkName = $"FK_{rm.Owner.Id}_{rm.MemberId}"; //TODO:特殊处理DbFirst导入表的外键约束名称
                            fks.Add($"ALTER TABLE \"{tableName}\" DROP CONSTRAINT \"{fkName}\";");
                        }
                    }
                }

                var cmdText = StringBuilderCache.GetStringAndRelease(sb);
                if (needCommand)
                {
                    //加入删除的外键SQL
                    for (int i = 0; i < fks.Count; i++)
                    {
                        sb.Insert(0, fks[i]);
                        sb.AppendLine();
                    }

                    commands.Add(new NpgsqlCommand(cmdText));
                }
                #endregion
            }

            //reset
            needCommand = false;
            fks.Clear();

            //处理新增的成员
            var addedMembers = model.Members.Where(t => t.PersistentState == PersistentState.Detached).ToArray();
            if (addedMembers != null && addedMembers.Length > 0)
            {
                #region ----新增的成员----
                sb = StringBuilderCache.Acquire();
                foreach (var m in addedMembers)
                {
                    if (m.Type == EntityMemberType.DataField)
                    {
                        needCommand = true;
                        sb.AppendFormat("ALTER TABLE \"{0}\" ADD COLUMN ", tableName);
                        BuildFieldDefine((DataFieldModel)m, sb, false);
                        sb.Append(";");
                    }
                    else if (m.Type == EntityMemberType.EntityRef)
                    {
                        var rm = (EntityRefModel)m;
                        if (!rm.IsAggregationRef) //只有非聚合引合创建外键
                        {
                            fks.Add(BuildForeignKey(rm, ctx, tableName));
                            //考虑CreateGetTreeNodeChildsDbFuncCommand
                        }
                    }
                }

                var cmdText = StringBuilderCache.GetStringAndRelease(sb);
                if (needCommand)
                {
                    //加入关系
                    sb.AppendLine();
                    for (int i = 0; i < fks.Count; i++)
                    {
                        sb.AppendLine(fks[i]);
                    }

                    commands.Add(new NpgsqlCommand(cmdText));
                }
                #endregion
            }

            //reset
            needCommand = false;
            fks.Clear();

            //处理修改的成员
            var changedMembers = model.Members.Where(t => t.PersistentState == PersistentState.Modified).ToArray();
            if (changedMembers != null && changedMembers.Length > 0)
            {
                #region ----修改的成员----
                foreach (var m in changedMembers)
                {
                    if (m.Type == EntityMemberType.DataField)
                    {
                        DataFieldModel dfm = (DataFieldModel)m;
                        //先处理数据类型变更,变更类型或者变更AllowNull或者变更默认值
                        if (dfm.IsDataTypeChanged)
                        {
                            sb = StringBuilderCache.Acquire();
                            sb.AppendFormat("ALTER TABLE \"{0}\" ALTER COLUMN ", tableName);
                            string defaultValue = BuildFieldDefine(dfm, sb, true);

                            if (dfm.AllowNull)
                            {
                                sb.AppendFormat(",ALTER COLUMN \"{0}\" DROP NOT NULL", dfm.SqlColOriginalName);
                            }
                            else
                            {
                                if (dfm.DataType == EntityFieldType.Binary)
                                {
                                    throw new Exception("Binary field must be allow null");
                                }
                                sb.AppendFormat(",ALTER COLUMN \"{0}\" SET NOT NULL,ALTER COLUMN \"{0}\" SET DEFAULT {1}",
                                                dfm.SqlColOriginalName, defaultValue);
                            }

                            commands.Add(new NpgsqlCommand(StringBuilderCache.GetStringAndRelease(sb)));
                        }

                        //再处理重命名列
                        if (m.IsNameChanged)
                        {
                            var renameColCmd = new NpgsqlCommand($"ALTER TABLE \"{tableName}\" RENAME COLUMN \"{dfm.SqlColOriginalName}\" TO \"{dfm.SqlColName}\"");
                            commands.Add(renameColCmd);
                        }
                    }

                    //TODO:处理EntityRef更新与删除规则
                    //注意不再需要同旧实现一样变更EntityRef的外键约束名称 "ALTER TABLE \"XXX\" RENAME CONSTRAINT \"XXX\" TO \"XXX\""
                    //因为ModelFirst的外键名称为FK_{MemberId};CodeFirst为导入的名称
                }
                #endregion
            }

            //处理索引变更
            BuildIndexes(model, commands, tableName);

            return(commands);
        }