diff --git a/packages/core/client/src/block-provider/hooks/index.ts b/packages/core/client/src/block-provider/hooks/index.ts
index 6fe470086..dfea313bb 100644
--- a/packages/core/client/src/block-provider/hooks/index.ts
+++ b/packages/core/client/src/block-provider/hooks/index.ts
@@ -1,7 +1,7 @@
 import { Schema, SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@formily/react';
 import { parse } from '@nocobase/utils/client';
 import { Modal, message } from 'antd';
-import { cloneDeep, isEqual, uniq, omitBy } from 'lodash';
+import { cloneDeep, uniq } from 'lodash';
 import get from 'lodash/get';
 import omit from 'lodash/omit';
 import { ChangeEvent, useContext, useEffect } from 'react';
@@ -16,12 +16,12 @@ import { transformToFilter } from '../../filter-provider/utils';
 import { useRecord } from '../../record-provider';
 import { removeNullCondition, useActionContext, useCompile } from '../../schema-component';
 import { BulkEditFormItemValueType } from '../../schema-initializer/components';
+import { useSchemaTemplateManager } from '../../schema-templates';
 import { useCurrentUserContext } from '../../user';
 import { useBlockRequestContext, useFilterByTk } from '../BlockProvider';
 import { useDetailsBlockContext } from '../DetailsBlockProvider';
 import { mergeFilter } from '../SharedFilterProvider';
 import { TableFieldResource } from '../TableFieldProvider';
-import { useSchemaTemplateManager } from '../../schema-templates';
 
 export const usePickActionProps = () => {
   const form = useForm();
@@ -158,8 +158,8 @@ export const useCreateActionProps = () => {
       if (!skipValidator) {
         await form.submit();
       }
-      const formValues = getFormValues(filterByTk, field, form, fieldNames, getField, resource);
-      const values = omitBy(formValues, (value) => isEqual(JSON.stringify(value), '[{}]'));
+      const values = getFormValues(filterByTk, field, form, fieldNames, getField, resource);
+      // const values = omitBy(formValues, (value) => isEqual(JSON.stringify(value), '[{}]'));
       if (addChild) {
         const treeParentField = getTreeParentField();
         values[treeParentField?.name ?? 'parent'] = currentRecord;
diff --git a/packages/core/client/src/collection-manager/interfaces/m2m.tsx b/packages/core/client/src/collection-manager/interfaces/m2m.tsx
index 1998730ec..9b51f0ba1 100644
--- a/packages/core/client/src/collection-manager/interfaces/m2m.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/m2m.tsx
@@ -1,12 +1,9 @@
 import { ISchema } from '@formily/react';
 import { uid } from '@formily/shared';
-import { cloneDeep } from 'lodash';
 import {
   defaultProps,
-  recordPickerSelector,
-  recordPickerViewer,
   relationshipType,
-  reverseFieldProperties,
+  reverseFieldProperties
 } from './properties';
 import { IField } from './types';
 
@@ -53,7 +50,7 @@ export const m2m: IField = {
   },
   availableTypes: ['belongsToMany'],
   schemaInitialize(schema: ISchema, { readPretty, block, targetCollection }) {
-    schema['type'] = 'array';
+    // schema['type'] = 'array';
     if (targetCollection?.titleField && schema['x-component-props']) {
       schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
       schema['x-component-props'].fieldNames.label = targetCollection.titleField;
diff --git a/packages/core/client/src/collection-manager/interfaces/m2o.tsx b/packages/core/client/src/collection-manager/interfaces/m2o.tsx
index 69c28a5a0..2ac8dc1e6 100644
--- a/packages/core/client/src/collection-manager/interfaces/m2o.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/m2o.tsx
@@ -1,11 +1,8 @@
 import { ISchema } from '@formily/react';
-import { cloneDeep } from 'lodash';
 import {
   constraintsProps,
-  recordPickerSelector,
-  recordPickerViewer,
   relationshipType,
-  reverseFieldProperties,
+  reverseFieldProperties
 } from './properties';
 import { IField } from './types';
 
@@ -52,7 +49,7 @@ export const m2o: IField = {
   },
   availableTypes: ['belongsTo'],
   schemaInitialize(schema: ISchema, { block, readPretty, targetCollection }) {
-    schema['type'] = 'object';
+    // schema['type'] = 'object';
     if (targetCollection?.titleField && schema['x-component-props']) {
       schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
       schema['x-component-props'].fieldNames.label = targetCollection.titleField;
diff --git a/packages/core/client/src/collection-manager/interfaces/o2m.tsx b/packages/core/client/src/collection-manager/interfaces/o2m.tsx
index 4267cca52..800e07502 100644
--- a/packages/core/client/src/collection-manager/interfaces/o2m.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/o2m.tsx
@@ -1,12 +1,5 @@
 import { ISchema } from '@formily/react';
-import { cloneDeep } from 'lodash';
-import {
-  constraintsProps,
-  recordPickerSelector,
-  recordPickerViewer,
-  relationshipType,
-  reverseFieldProperties,
-} from './properties';
+import { constraintsProps, relationshipType, reverseFieldProperties } from './properties';
 import { IField } from './types';
 
 export const o2m: IField = {
@@ -52,7 +45,7 @@ export const o2m: IField = {
   },
   availableTypes: ['hasMany'],
   schemaInitialize(schema: ISchema, { field, block, readPretty, targetCollection }) {
-    schema['type'] = 'array';
+    // schema['type'] = 'array';
     if (targetCollection?.titleField && schema['x-component-props']) {
       schema['x-component-props'].fieldNames = schema['x-component-props'].fieldNames || { value: 'id' };
       schema['x-component-props'].fieldNames.label = targetCollection.titleField;
diff --git a/packages/core/client/src/collection-manager/interfaces/o2o.tsx b/packages/core/client/src/collection-manager/interfaces/o2o.tsx
index f72aa926e..82610e2da 100644
--- a/packages/core/client/src/collection-manager/interfaces/o2o.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/o2o.tsx
@@ -1,12 +1,5 @@
 import { ISchema } from '@formily/react';
-import { cloneDeep } from 'lodash';
-import {
-  constraintsProps,
-  recordPickerSelector,
-  recordPickerViewer,
-  relationshipType,
-  reverseFieldProperties,
-} from './properties';
+import { constraintsProps, relationshipType, reverseFieldProperties } from './properties';
 import { IField } from './types';
 
 export const o2o: IField = {
@@ -231,7 +224,7 @@ export const oho: IField = {
     },
   },
   schemaInitialize(schema: ISchema, { field, block, readPretty, action }) {
-    schema['type'] = 'object';
+    // schema['type'] = 'object';
     if (['Table', 'Kanban'].includes(block)) {
       schema['x-component-props'] = schema['x-component-props'] || {};
       schema['x-component-props']['ellipsis'] = true;
@@ -401,7 +394,7 @@ export const obo: IField = {
     },
   },
   schemaInitialize(schema: ISchema, { field, block, readPretty, action, targetCollection }) {
-    schema['type'] = 'object';
+    // schema['type'] = 'object';
     if (['Table', 'Kanban'].includes(block)) {
       schema['x-component-props'] = schema['x-component-props'] || {};
       schema['x-component-props']['ellipsis'] = true;
diff --git a/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx b/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx
index d8e09342a..33fdbecc9 100644
--- a/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx
+++ b/packages/core/client/src/schema-component/antd/association-field/AssociationFieldProvider.tsx
@@ -1,10 +1,11 @@
+import { Field } from '@formily/core';
 import { observer, useField, useFieldSchema } from '@formily/react';
 import React, { useMemo } from 'react';
 import { useCollectionManager } from '../../../collection-manager';
 import { AssociationFieldContext } from './context';
 
 export const AssociationFieldProvider = observer((props) => {
-  const field = useField();
+  const field = useField<Field>();
   const { getCollectionJoinField, getCollection } = useCollectionManager();
   const fieldSchema = useFieldSchema();
 
@@ -20,6 +21,7 @@ export const AssociationFieldProvider = observer((props) => {
     () => fieldSchema['x-component-props']?.mode || (isFileCollection ? 'FileManager' : 'Select'),
     [fieldSchema['x-component-props']?.mode],
   );
+
   return collectionField ? (
     <AssociationFieldContext.Provider value={{ options: collectionField, field, currentMode }}>
       {props.children}
diff --git a/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx b/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx
index e33b47fee..2e9a25aad 100644
--- a/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx
+++ b/packages/core/client/src/schema-component/antd/association-field/AssociationSelect.tsx
@@ -1,8 +1,7 @@
 import { LoadingOutlined } from '@ant-design/icons';
 import { RecursionField, connect, mapProps, observer, useField, useFieldSchema } from '@formily/react';
 import { Input } from 'antd';
-import React, { useCallback, useEffect, useMemo } from 'react';
-import { useFieldTitle } from '../../hooks';
+import React from 'react';
 import { RemoteSelect, RemoteSelectProps } from '../remote-select';
 import useServiceOptions from './hooks';
 
@@ -17,28 +16,8 @@ const InternalAssociationSelect = observer((props: AssociationSelectProps) => {
   const fieldSchema = useFieldSchema();
   const service = useServiceOptions(props);
   const isAllowAddNew = fieldSchema['x-add-new'];
-  const normalizeValues = useCallback(
-    (obj) => {
-      if (!objectValue && typeof obj === 'object') {
-        return obj[fieldNames?.value];
-      }
-      return obj;
-    },
-    [objectValue, fieldNames?.value],
-  );
-  const value = useMemo(() => {
-    if (props.value === undefined || props.value === null || !Object.keys(props.value).length) {
-      return;
-    }
-    if (Array.isArray(props.value)) {
-      return props.value;
-    } else {
-      return props.value;
-    }
-  }, [props.value, normalizeValues]);
-  useEffect(() => {
-    field.value = value;
-  }, []);
+  const value = Array.isArray(props.value) ? props.value.filter(Boolean) : props.value;
+
   return (
     <div key={fieldSchema.name}>
       <Input.Group compact style={{ display: 'flex' }}>
@@ -75,9 +54,8 @@ export const AssociationSelect = InternalAssociationSelect as unknown as Associa
 
 export const AssociationSelectReadPretty = connect(
   (props: any) => {
+    const service = useServiceOptions(props);
     if (props.fieldNames) {
-      const service = useServiceOptions(props);
-      useFieldTitle();
       return <RemoteSelect.ReadPretty {...props} service={service}></RemoteSelect.ReadPretty>;
     }
     return null;
diff --git a/packages/core/client/src/schema-component/antd/association-field/Editable.tsx b/packages/core/client/src/schema-component/antd/association-field/Editable.tsx
index 692518081..d85f516a0 100644
--- a/packages/core/client/src/schema-component/antd/association-field/Editable.tsx
+++ b/packages/core/client/src/schema-component/antd/association-field/Editable.tsx
@@ -1,5 +1,5 @@
 import { observer, useField, useFieldSchema, useForm } from '@formily/react';
-import React from 'react';
+import React, { useEffect, useState } from 'react';
 import { SchemaComponentOptions } from '../../';
 import { useAssociationCreateActionProps as useCAP } from '../../../block-provider/hooks';
 import { AssociationFieldProvider } from './AssociationFieldProvider';
@@ -17,6 +17,31 @@ const EditableAssociationField = observer((props: any) => {
   const form = useForm();
   const fieldSchema = useFieldSchema();
   const { options: collectionField, currentMode } = useAssociationFieldContext();
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    setLoading(true);
+    if (!collectionField) {
+      setLoading(false);
+      return;
+    }
+    if (field.value !== null && field.value !== undefined) {
+      setLoading(false);
+      return;
+    }
+    if (currentMode === 'Nester') {
+      if (['belongsTo', 'hasOne'].includes(collectionField.type)) {
+        field.value = {};
+      } else if (['belongsToMany', 'hasMany'].includes(collectionField.type)) {
+        field.value = [null];
+      }
+    }
+    setLoading(false);
+  }, [currentMode, collectionField, field.value]);
+
+  if (loading) {
+    return null;
+  }
 
   const useCreateActionProps = () => {
     const { onClick } = useCAP();
diff --git a/packages/core/client/src/schema-component/antd/association-field/InternalPicker.tsx b/packages/core/client/src/schema-component/antd/association-field/InternalPicker.tsx
index 5c5d72394..663b22fa3 100644
--- a/packages/core/client/src/schema-component/antd/association-field/InternalPicker.tsx
+++ b/packages/core/client/src/schema-component/antd/association-field/InternalPicker.tsx
@@ -1,7 +1,7 @@
 import { RecursionField, observer, useField, useFieldSchema } from '@formily/react';
 import { Input, Select } from 'antd';
 import { differenceBy, unionBy } from 'lodash';
-import React, { useContext, useEffect, useState } from 'react';
+import React, { useContext, useEffect, useMemo, useState } from 'react';
 import {
   FormProvider,
   RecordPickerContext,
@@ -71,7 +71,20 @@ export const InternalPicker = observer((props: any) => {
   const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label');
   const isAllowAddNew = fieldSchema['x-add-new'];
   const [selectedRows, setSelectedRows] = useState([]);
-  const [options, setOptions] = useState([]);
+  const options = useMemo(() => {
+    if (value && Object.keys(value).length > 0) {
+      const opts = (Array.isArray(value) ? value : value ? [value] : []).filter(Boolean).map((option) => {
+        const label = option?.[fieldNames.label];
+        return {
+          ...option,
+          [fieldNames.label]: getLabelFormatValue(compile(labelUiSchema), compile(label)),
+        };
+      });
+      return opts;
+    }
+    return [];
+  }, [value, fieldNames?.label]);
+
   const pickerProps = {
     size: 'small',
     fieldNames,
@@ -85,24 +98,11 @@ export const InternalPicker = observer((props: any) => {
     setSelectedRows,
     collectionField,
   };
-  useEffect(() => {
-    if (value && Object.keys(value).length > 0) {
-      const opts = (Array.isArray(value) ? value : value ? [value] : []).map((option) => {
-        const label = option[fieldNames.label];
-        return {
-          ...option,
-          [fieldNames.label]: getLabelFormatValue(compile(labelUiSchema), compile(label)),
-        };
-      });
-      setOptions(opts);
-    }
-  }, [value, fieldNames?.label]);
 
   const getValue = () => {
     if (multiple == null) return null;
-    return Array.isArray(value) ? value?.map((v) => v[fieldNames.value]) : value?.[fieldNames.value];
+    return Array.isArray(value) ? value.filter(Boolean)?.map((v) => v?.[fieldNames.value]) : value?.[fieldNames.value];
   };
-
   const getFilter = () => {
     const targetKey = collectionField?.targetKey || 'id';
     const list = options.map((option) => option[targetKey]).filter(Boolean);
diff --git a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx
index e2b3e61fa..4ad58961e 100644
--- a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx
+++ b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx
@@ -2,7 +2,7 @@ import { CloseCircleOutlined } from '@ant-design/icons';
 import { ArrayField } from '@formily/core';
 import { RecursionField, observer, useFieldSchema } from '@formily/react';
 import { Button, Card, Divider } from 'antd';
-import React, { useContext, useEffect, useState } from 'react';
+import React, { useContext } from 'react';
 import { useTranslation } from 'react-i18next';
 import { AssociationFieldContext } from './context';
 import { useAssociationFieldContext } from './hooks';
@@ -22,28 +22,13 @@ const ToOneNester = (props) => {
   return <Card bordered={true}>{props.children}</Card>;
 };
 
-const toArr = (value, isReadpretty) => {
-  if (!value) {
-    return isReadpretty ? [] : [{}];
-  }
-  if (Array.isArray(value)) {
-    return value.length > 0 ? value : isReadpretty ? [] : [{}];
-  }
-  return [value];
-};
-
 const ToManyNester = observer((props) => {
   const fieldSchema = useFieldSchema();
   const { field } = useAssociationFieldContext<ArrayField>();
-  const [values, setValues] = useState([]);
-  useEffect(() => {
-    const values = toArr(field.value, field.readPretty);
-    setValues(values);
-  }, []);
   const { t } = useTranslation();
   return (
     <Card bordered={true} style={{ position: 'relative' }}>
-      {values.map((value, index) => {
+      {(field.value || []).map((value, index) => {
         return (
           <>
             {!field.readPretty && (
@@ -51,9 +36,9 @@ const ToManyNester = observer((props) => {
                 <CloseCircleOutlined
                   style={{ zIndex: 1000, position: 'absolute', color: '#a8a3a3' }}
                   onClick={() => {
-                    const data = values.concat();
-                    data.splice(index, 1);
-                    setValues(data);
+                    const result = field.value;
+                    result.splice(index, 1);
+                    field.value = result;
                   }}
                 />
               </div>
@@ -68,9 +53,9 @@ const ToManyNester = observer((props) => {
           type={'dashed'}
           block
           onClick={() => {
-            const data = values.concat();
-            data.push({});
-            setValues(data);
+            const result = field.value;
+            result.push({});
+            field.value = result;
           }}
         >
           {t('Add new')}
diff --git a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx
index 3664964b8..872127498 100644
--- a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx
+++ b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx
@@ -172,7 +172,7 @@ FormItem.Designer = function Designer() {
         };
   });
 
-  const fieldSchemaWithoutRequired = _.omit(fieldSchema,'required')
+  const fieldSchemaWithoutRequired = _.omit(fieldSchema, 'required');
 
   return (
     <GeneralSchemaDesigner>
@@ -574,10 +574,10 @@ FormItem.Designer = function Designer() {
             schema['x-component-props'] = fieldSchema['x-component-props'];
             field.componentProps = field.componentProps || {};
             field.componentProps.mode = mode;
-            if (mode === 'Nester') {
-              const initValue = ['hasMany', 'belongsToMany'].includes(collectionField?.type) ? [] : {};
-              field.value = field.value || initValue;
-            }
+            // if (mode === 'Nester') {
+            //   const initValue = ['hasMany', 'belongsToMany'].includes(collectionField?.type) ? [{}] : {};
+            //   field.value = field.value || initValue;
+            // }
             dn.emit('patch', {
               schema,
             });
diff --git a/packages/core/database/src/update-guard.ts b/packages/core/database/src/update-guard.ts
index 7f696266d..bc5192609 100644
--- a/packages/core/database/src/update-guard.ts
+++ b/packages/core/database/src/update-guard.ts
@@ -111,7 +111,7 @@ export class UpdateGuard {
 
       if (Array.isArray(associationValues)) {
         associationValues = associationValues.map((value) => {
-          if (typeof value == 'string' || typeof value == 'number') {
+          if (value === undefined || value === null || typeof value == 'string' || typeof value == 'number') {
             return value;
           } else {
             return sanitizeValue(value);
diff --git a/packages/plugins/ui-schema-storage/src/migrations/20230522231231-association-field.ts b/packages/plugins/ui-schema-storage/src/migrations/20230522231231-association-field.ts
new file mode 100644
index 000000000..e60f8fb7e
--- /dev/null
+++ b/packages/plugins/ui-schema-storage/src/migrations/20230522231231-association-field.ts
@@ -0,0 +1,45 @@
+import { Migration } from '@nocobase/server';
+import UiSchemaRepository from '../repository';
+
+export default class extends Migration {
+  async up() {
+    const result = await this.app.version.satisfies('<0.9.3-alpha.2');
+
+    if (!result) {
+      return;
+    }
+
+    const r = this.db.getRepository<UiSchemaRepository>('uiSchemas');
+    const items = await r.find({
+      filter: {
+        'schema.x-component': 'CollectionField',
+      },
+    });
+    console.log(items?.length);
+    await this.db.sequelize.transaction(async (transaction) => {
+      for (const item of items) {
+        const schema = item.schema;
+        if (!schema['x-collection-field']) {
+          continue;
+        }
+        if (schema['type'] === 'string') {
+          continue;
+        }
+        const field = this.db.getFieldByPath(schema['x-collection-field']);
+        if (!field) {
+          continue;
+        }
+        console.log(schema['x-collection-field'], schema['type']);
+        if (['hasOne', 'belongsTo'].includes(field.type)) {
+          schema['type'] = 'string';
+        } else if (['hasMany', 'belongsToMany'].includes(field.type)) {
+          schema['type'] = 'string';
+        } else {
+          continue;
+        }
+        item.set('schema', schema);
+        await item.save({ transaction });
+      }
+    });
+  }
+}