This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new c9054565fd [#7381] feat(model): Backend supports multiple URIs for 
model version (#7502)
c9054565fd is described below

commit c9054565fd70c89a82899ef0311fc2539e986873
Author: XiaoZ <[email protected]>
AuthorDate: Mon Jul 7 10:21:26 2025 +0800

    [#7381] feat(model): Backend supports multiple URIs for model version 
(#7502)
    
    ### What changes were proposed in this pull request?
    
    Backend supports multiple URIs for model version.
    
    ### Why are the changes needed?
    
    Fix: #7381
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    UTs.
    
    ---------
    
    Co-authored-by: zhanghan <[email protected]>
---
 .../catalog/model/ModelCatalogOperations.java      |   9 +-
 .../apache/gravitino/meta/ModelVersionEntity.java  |  28 ++--
 .../relational/mapper/ModelVersionMetaMapper.java  |  17 ++-
 .../mapper/ModelVersionMetaSQLProviderFactory.java |  17 ++-
 .../base/ModelVersionMetaBaseSQLProvider.java      |  80 +++++++----
 .../provider/h2/ModelVersionMetaH2Provider.java    |  57 ++++++++
 .../storage/relational/po/ModelVersionPO.java      |  10 ++
 .../service/ModelVersionMetaService.java           |  98 +++++++++-----
 .../storage/relational/utils/POConverters.java     |  53 +++++---
 .../gravitino/cache/TestCaffeineEntityCache.java   |   3 +-
 .../gravitino/meta/TestModelVersionEntity.java     |  43 +++---
 .../gravitino/storage/TestEntityStorage.java       |   7 +-
 .../storage/relational/TestJDBCBackend.java        |   4 +-
 .../service/TestModelVersionMetaService.java       | 148 ++++++++++++++++++---
 .../storage/relational/utils/TestPOConverters.java |  67 ++++------
 .../java/org/apache/gravitino/utils/TestUtil.java  |   9 +-
 scripts/h2/schema-1.0.0-h2.sql                     |   3 +-
 scripts/h2/upgrade-0.9.0-to-1.0.0-h2.sql           |   9 +-
 scripts/mysql/schema-1.0.0-mysql.sql               |   3 +-
 scripts/mysql/upgrade-0.9.0-to-1.0.0-mysql.sql     |   7 +
 scripts/postgresql/schema-1.0.0-postgresql.sql     |   4 +-
 .../upgrade-0.9.0-to-1.0.0-postgresql.sql          |   8 ++
 22 files changed, 502 insertions(+), 182 deletions(-)

diff --git 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
index ee83ae4d6d..9fda7c72b3 100644
--- 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
+++ 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
@@ -19,6 +19,7 @@
 package org.apache.gravitino.catalog.model;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -244,7 +245,7 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
             // executing the insert operation.
             .withVersion(INIT_VERSION)
             .withAliases(aliasList)
-            .withUri(uri)
+            .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, uri))
             .withComment(comment)
             .withProperties(properties)
             .withAuditInfo(
@@ -430,7 +431,7 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
         modelVersionEntity.aliases() == null
             ? Lists.newArrayList()
             : Lists.newArrayList(modelVersionEntity.aliases());
-    String entityUri = modelVersionEntity.uri();
+    String entityUri = 
modelVersionEntity.uris().get(ModelVersion.URI_NAME_UNKNOWN);
     Map<String, String> entityProperties =
         modelVersionEntity.properties() == null
             ? Maps.newHashMap()
@@ -477,7 +478,7 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
         .withModelIdentifier(entityModelIdentifier)
         .withAliases(entityAliases)
         .withComment(entityComment)
-        .withUri(entityUri)
+        .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, entityUri))
         .withProperties(entityProperties)
         .withAuditInfo(
             AuditInfo.builder()
@@ -503,7 +504,7 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
     return ModelVersionImpl.builder()
         .withVersion(modelVersion.version())
         .withAliases(modelVersion.aliases().toArray(new String[0]))
-        .withUri(modelVersion.uri())
+        .withUri(modelVersion.uris().get(ModelVersion.URI_NAME_UNKNOWN))
         .withComment(modelVersion.comment())
         .withProperties(modelVersion.properties())
         .withAuditInfo(modelVersion.auditInfo())
diff --git 
a/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java 
b/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java
index 733c1315b5..478b99946d 100644
--- a/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java
@@ -18,6 +18,7 @@
  */
 package org.apache.gravitino.meta;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import java.util.Collections;
@@ -45,8 +46,8 @@ public class ModelVersionEntity implements Entity, Auditable, 
HasIdentifier {
       Field.optional("comment", String.class, "The comment or description of 
the model entity.");
   public static final Field ALIASES =
       Field.optional("aliases", List.class, "The aliases of the model 
entity.");
-  public static final Field URL =
-      Field.required("uri", String.class, "The URI of the model entity.");
+  public static final Field URIS =
+      Field.required("uris", Map.class, "The URIs and their names of the model 
version entity.");
   public static final Field PROPERTIES =
       Field.optional("properties", Map.class, "The properties of the model 
entity.");
   public static final Field AUDIT_INFO =
@@ -60,7 +61,7 @@ public class ModelVersionEntity implements Entity, Auditable, 
HasIdentifier {
 
   private List<String> aliases;
 
-  private String uri;
+  private Map<String, String> uris;
 
   private AuditInfo auditInfo;
 
@@ -75,7 +76,7 @@ public class ModelVersionEntity implements Entity, Auditable, 
HasIdentifier {
     fields.put(VERSION, version);
     fields.put(COMMENT, comment);
     fields.put(ALIASES, aliases);
-    fields.put(URL, uri);
+    fields.put(URIS, uris);
     fields.put(PROPERTIES, properties);
     fields.put(AUDIT_INFO, auditInfo);
 
@@ -98,8 +99,8 @@ public class ModelVersionEntity implements Entity, Auditable, 
HasIdentifier {
     return aliases;
   }
 
-  public String uri() {
-    return uri;
+  public Map<String, String> uris() {
+    return uris;
   }
 
   public Map<String, String> properties() {
@@ -133,6 +134,13 @@ public class ModelVersionEntity implements Entity, 
Auditable, HasIdentifier {
     throw new UnsupportedOperationException("Model version entity does not 
have an ID.");
   }
 
+  @Override
+  public void validate() throws IllegalArgumentException {
+    Entity.super.validate();
+    Preconditions.checkArgument(
+        !uris.isEmpty(), "The uri of the model version entity must not be 
empty.");
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -148,14 +156,14 @@ public class ModelVersionEntity implements Entity, 
Auditable, HasIdentifier {
         && Objects.equals(modelIdent, that.modelIdent)
         && Objects.equals(comment, that.comment)
         && CollectionUtils.isEqualCollection(aliases, that.aliases)
-        && Objects.equals(uri, that.uri)
+        && Objects.equals(uris, that.uris)
         && Objects.equals(properties, that.properties)
         && Objects.equals(auditInfo, that.auditInfo);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(modelIdent, version, comment, aliases, uri, 
properties, auditInfo);
+    return Objects.hash(modelIdent, version, comment, aliases, uris, 
properties, auditInfo);
   }
 
   public static Builder builder() {
@@ -189,8 +197,8 @@ public class ModelVersionEntity implements Entity, 
Auditable, HasIdentifier {
       return this;
     }
 
-    public Builder withUri(String uri) {
-      model.uri = uri;
+    public Builder withUris(Map<String, String> uris) {
+      model.uris = uris;
       return this;
     }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
index aa7cc7e365..ccf6ea48d4 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
@@ -19,6 +19,7 @@
 package org.apache.gravitino.storage.relational.mapper;
 
 import java.util.List;
+import java.util.Map;
 import org.apache.gravitino.storage.relational.po.ModelVersionPO;
 import org.apache.ibatis.annotations.DeleteProvider;
 import org.apache.ibatis.annotations.InsertProvider;
@@ -32,8 +33,8 @@ public interface ModelVersionMetaMapper {
 
   @InsertProvider(
       type = ModelVersionMetaSQLProviderFactory.class,
-      method = "insertModelVersionMeta")
-  void insertModelVersionMeta(@Param("modelVersionMeta") ModelVersionPO 
modelVersionPO);
+      method = "insertModelVersionMetas")
+  void insertModelVersionMetas(@Param("modelVersionMetas") 
List<ModelVersionPO> modelVersionPOs);
 
   @SelectProvider(
       type = ModelVersionMetaSQLProviderFactory.class,
@@ -43,13 +44,13 @@ public interface ModelVersionMetaMapper {
   @SelectProvider(
       type = ModelVersionMetaSQLProviderFactory.class,
       method = "selectModelVersionMeta")
-  ModelVersionPO selectModelVersionMeta(
+  List<ModelVersionPO> selectModelVersionMeta(
       @Param("modelId") Long modelId, @Param("modelVersion") Integer 
modelVersion);
 
   @SelectProvider(
       type = ModelVersionMetaSQLProviderFactory.class,
       method = "selectModelVersionMetaByAlias")
-  ModelVersionPO selectModelVersionMetaByAlias(
+  List<ModelVersionPO> selectModelVersionMetaByAlias(
       @Param("modelId") Long modelId, @Param("alias") String alias);
 
   @UpdateProvider(
@@ -97,4 +98,12 @@ public interface ModelVersionMetaMapper {
   Integer updateModelVersionMeta(
       @Param("newModelVersionMeta") ModelVersionPO newModelVersionPO,
       @Param("oldModelVersionMeta") ModelVersionPO oldModelVersionPO);
+
+  @UpdateProvider(
+      type = ModelVersionMetaSQLProviderFactory.class,
+      method = "updateModelVersionUris")
+  Integer updateModelVersionUris(
+      @Param("modelId") Long modelId,
+      @Param("modelVersion") Integer modelVersion,
+      @Param("uris") Map<String, String> uris);
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
index 3a5ef7fba1..f0dce961b7 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
@@ -19,9 +19,11 @@
 package org.apache.gravitino.storage.relational.mapper;
 
 import com.google.common.collect.ImmutableMap;
+import java.util.List;
 import java.util.Map;
 import org.apache.gravitino.storage.relational.JDBCBackend.JDBCBackendType;
 import 
org.apache.gravitino.storage.relational.mapper.provider.base.ModelVersionMetaBaseSQLProvider;
+import 
org.apache.gravitino.storage.relational.mapper.provider.h2.ModelVersionMetaH2Provider;
 import 
org.apache.gravitino.storage.relational.mapper.provider.postgresql.ModelVersionMetaPostgreSQLProvider;
 import org.apache.gravitino.storage.relational.po.ModelVersionPO;
 import org.apache.gravitino.storage.relational.session.SqlSessionFactoryHelper;
@@ -31,8 +33,6 @@ public class ModelVersionMetaSQLProviderFactory {
 
   static class ModelVersionMetaMySQLProvider extends 
ModelVersionMetaBaseSQLProvider {}
 
-  static class ModelVersionMetaH2Provider extends 
ModelVersionMetaBaseSQLProvider {}
-
   private static final Map<JDBCBackendType, ModelVersionMetaBaseSQLProvider>
       MODEL_VERSION_META_SQL_PROVIDER_MAP =
           ImmutableMap.of(
@@ -51,9 +51,9 @@ public class ModelVersionMetaSQLProviderFactory {
     return MODEL_VERSION_META_SQL_PROVIDER_MAP.get(jdbcBackendType);
   }
 
-  public static String insertModelVersionMeta(
-      @Param("modelVersionMeta") ModelVersionPO modelVersionPO) {
-    return getProvider().insertModelVersionMeta(modelVersionPO);
+  public static String insertModelVersionMetas(
+      @Param("modelVersionMetas") List<ModelVersionPO> modelVersionPOs) {
+    return getProvider().insertModelVersionMetas(modelVersionPOs);
   }
 
   public static String listModelVersionMetasByModelId(@Param("modelId") Long 
modelId) {
@@ -108,4 +108,11 @@ public class ModelVersionMetaSQLProviderFactory {
       @Param("oldModelVersionMeta") ModelVersionPO oldModelVersionPO) {
     return getProvider().updateModelVersionMeta(newModelVersionPO, 
oldModelVersionPO);
   }
+
+  public static String updateModelVersionUris(
+      @Param("modelId") Long modelId,
+      @Param("modelVersion") Integer modelVersion,
+      @Param("uris") Map<String, String> uris) {
+    return getProvider().updateModelVersionUris(modelId, modelVersion, uris);
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
index 6fffd7f56b..7baf7bb3ac 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
@@ -18,6 +18,8 @@
  */
 package org.apache.gravitino.storage.relational.mapper.provider.base;
 
+import java.util.List;
+import java.util.Map;
 import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import 
org.apache.gravitino.storage.relational.mapper.ModelVersionAliasRelMapper;
 import org.apache.gravitino.storage.relational.mapper.ModelVersionMetaMapper;
@@ -26,27 +28,38 @@ import org.apache.ibatis.annotations.Param;
 
 public class ModelVersionMetaBaseSQLProvider {
 
-  public String insertModelVersionMeta(@Param("modelVersionMeta") 
ModelVersionPO modelVersionPO) {
-    return "INSERT INTO "
+  public String insertModelVersionMetas(
+      @Param("modelVersionMetas") List<ModelVersionPO> modelVersionPOs) {
+    return "<script>"
+        + "INSERT INTO "
         + ModelVersionMetaMapper.TABLE_NAME
-        + "(metalake_id, catalog_id, schema_id, model_id, version,"
-        + " model_version_comment, model_version_properties, 
model_version_uri,"
-        + " audit_info, deleted_at)"
-        + " SELECT metalake_id, catalog_id, schema_id, model_id, 
model_latest_version,"
-        + " #{modelVersionMeta.modelVersionComment}, 
#{modelVersionMeta.modelVersionProperties},"
-        + " #{modelVersionMeta.modelVersionUri}, 
#{modelVersionMeta.auditInfo},"
-        + " #{modelVersionMeta.deletedAt}"
+        + "(metalake_id, catalog_id, schema_id, model_id, version, 
model_version_comment,"
+        + " model_version_properties, model_version_uri_name, 
model_version_uri, audit_info, deleted_at)"
+        + " SELECT m.metalake_id, m.catalog_id, m.schema_id, m.model_id, 
m.model_latest_version, v.model_version_comment,"
+        + " v.model_version_properties, v.model_version_uri_name, 
v.model_version_uri, v.audit_info, v.deleted_at"
+        + " FROM ("
+        + "<foreach collection='modelVersionMetas' item='version' 
separator='UNION ALL'>"
+        + " SELECT"
+        + " #{version.modelId} AS model_id, #{version.modelVersionComment} AS 
model_version_comment,"
+        + " #{version.modelVersionProperties} AS model_version_properties, 
#{version.auditInfo} AS audit_info,"
+        + " #{version.deletedAt} AS deleted_at, #{version.modelVersionUriName} 
AS model_version_uri_name,"
+        + " #{version.modelVersionUri} AS model_version_uri "
+        + "</foreach>"
+        + " ) v"
+        + " JOIN"
+        + " (SELECT metalake_id, catalog_id, schema_id, model_id, 
model_latest_version"
         + " FROM "
         + ModelMetaMapper.TABLE_NAME
-        + " WHERE model_id = #{modelVersionMeta.modelId} AND deleted_at = 0";
+        + " WHERE model_id = #{modelVersionMetas[0].modelId} AND deleted_at = 
0) m"
+        + " ON v.model_id = m.model_id"
+        + "</script>";
   }
 
   public String listModelVersionMetasByModelId(@Param("modelId") Long modelId) 
{
-    return "SELECT metalake_id AS metalakeId, catalog_id AS catalogId,"
-        + " schema_id AS schemaId, model_id AS modelId, version AS 
modelVersion,"
-        + " model_version_comment AS modelVersionComment, 
model_version_properties AS"
-        + " modelVersionProperties, model_version_uri AS modelVersionUri, 
audit_info AS"
-        + " auditInfo, deleted_at AS deletedAt"
+    return "SELECT metalake_id AS metalakeId, catalog_id AS catalogId, 
schema_id AS schemaId,"
+        + " model_id AS modelId, version AS modelVersion, 
model_version_comment AS modelVersionComment,"
+        + " model_version_properties AS modelVersionProperties, 
model_version_uri_name AS modelVersionUriName,"
+        + " model_version_uri AS modelVersionUri, audit_info AS auditInfo, 
deleted_at AS deletedAt"
         + " FROM "
         + ModelVersionMetaMapper.TABLE_NAME
         + " WHERE model_id = #{modelId} AND deleted_at = 0";
@@ -54,11 +67,10 @@ public class ModelVersionMetaBaseSQLProvider {
 
   public String selectModelVersionMeta(
       @Param("modelId") Long modelId, @Param("modelVersion") Integer 
modelVersion) {
-    return "SELECT metalake_id AS metalakeId, catalog_id AS catalogId,"
-        + " schema_id AS schemaId, model_id AS modelId, version AS 
modelVersion,"
-        + " model_version_comment AS modelVersionComment, 
model_version_properties AS"
-        + " modelVersionProperties, model_version_uri AS modelVersionUri, 
audit_info AS"
-        + " auditInfo, deleted_at AS deletedAt"
+    return "SELECT metalake_id AS metalakeId, catalog_id AS catalogId, 
schema_id AS schemaId, "
+        + " model_id AS modelId, version AS modelVersion, 
model_version_comment AS modelVersionComment,"
+        + " model_version_properties AS modelVersionProperties, 
model_version_uri_name AS modelVersionUriName,"
+        + " model_version_uri AS modelVersionUri, audit_info AS auditInfo, 
deleted_at AS deletedAt"
         + " FROM "
         + ModelVersionMetaMapper.TABLE_NAME
         + " WHERE model_id = #{modelId} AND version = #{modelVersion} AND 
deleted_at = 0";
@@ -66,11 +78,10 @@ public class ModelVersionMetaBaseSQLProvider {
 
   public String selectModelVersionMetaByAlias(
       @Param("modelId") Long modelId, @Param("alias") String alias) {
-    return "SELECT mvi.metalake_id AS metalakeId, mvi.catalog_id AS catalogId,"
-        + " mvi.schema_id AS schemaId, mvi.model_id AS modelId, mvi.version AS 
modelVersion,"
-        + " mvi.model_version_comment AS modelVersionComment, 
mvi.model_version_properties AS"
-        + " modelVersionProperties, mvi.model_version_uri AS modelVersionUri, 
mvi.audit_info AS"
-        + " auditInfo, mvi.deleted_at AS deletedAt"
+    return "SELECT mvi.metalake_id AS metalakeId, mvi.catalog_id AS catalogId, 
mvi.schema_id AS schemaId,"
+        + " mvi.model_id AS modelId, mvi.version AS modelVersion, 
mvi.model_version_comment AS modelVersionComment,"
+        + " mvi.model_version_properties AS modelVersionProperties, 
mvi.model_version_uri_name AS modelVersionUriName,"
+        + " mvi.model_version_uri AS modelVersionUri, mvi.audit_info AS 
auditInfo, mvi.deleted_at AS deletedAt"
         + " FROM "
         + ModelVersionMetaMapper.TABLE_NAME
         + " mvi"
@@ -162,7 +173,6 @@ public class ModelVersionMetaBaseSQLProvider {
         + "version = #{newModelVersionMeta.modelVersion}, "
         + "model_version_comment = #{newModelVersionMeta.modelVersionComment}, 
"
         + "model_version_properties = 
#{newModelVersionMeta.modelVersionProperties}, "
-        + "model_version_uri = #{newModelVersionMeta.modelVersionUri}, "
         + "audit_info = #{newModelVersionMeta.auditInfo}, "
         + "deleted_at = #{newModelVersionMeta.deletedAt} "
         + "WHERE model_id = #{oldModelVersionMeta.modelId} "
@@ -172,8 +182,24 @@ public class ModelVersionMetaBaseSQLProvider {
         + "AND version = #{oldModelVersionMeta.modelVersion} "
         + "AND model_version_comment = 
#{oldModelVersionMeta.modelVersionComment} "
         + "AND model_version_properties = 
#{oldModelVersionMeta.modelVersionProperties} "
-        + "AND model_version_uri = #{oldModelVersionMeta.modelVersionUri} "
         + "AND audit_info = #{oldModelVersionMeta.auditInfo} "
         + "AND deleted_at = 0";
   }
+
+  public String updateModelVersionUris(
+      @Param("modelId") Long modelId,
+      @Param("modelVersion") Integer modelVersion,
+      @Param("uris") Map<String, String> uris) {
+    return "<script>"
+        + "UPDATE "
+        + ModelVersionMetaMapper.TABLE_NAME
+        + " SET"
+        + " model_version_uri = CASE"
+        + "<foreach collection='uris' index='k' item='v' separator=''>"
+        + " WHEN model_version_uri_name = #{k} THEN #{v}"
+        + "</foreach>"
+        + " ELSE model_version_uri END"
+        + " WHERE model_id = #{modelId} AND version = #{modelVersion} AND 
deleted_at = 0"
+        + "</script>";
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/h2/ModelVersionMetaH2Provider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/h2/ModelVersionMetaH2Provider.java
new file mode 100644
index 0000000000..81d33e435e
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/h2/ModelVersionMetaH2Provider.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.storage.relational.mapper.provider.h2;
+
+import java.util.List;
+import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.ModelVersionMetaMapper;
+import 
org.apache.gravitino.storage.relational.mapper.provider.base.ModelVersionMetaBaseSQLProvider;
+import org.apache.gravitino.storage.relational.po.ModelVersionPO;
+import org.apache.ibatis.annotations.Param;
+
+public class ModelVersionMetaH2Provider extends 
ModelVersionMetaBaseSQLProvider {
+
+  @Override
+  public String insertModelVersionMetas(
+      @Param("modelVersionMetas") List<ModelVersionPO> modelVersionPOs) {
+    return "<script>"
+        + "INSERT INTO "
+        + ModelVersionMetaMapper.TABLE_NAME
+        + "(metalake_id, catalog_id, schema_id, model_id, version, 
model_version_comment,"
+        + " model_version_properties, model_version_uri_name, 
model_version_uri, audit_info, deleted_at)"
+        + " SELECT m.metalake_id, m.catalog_id, m.schema_id, m.model_id, 
m.model_latest_version, v.model_version_comment,"
+        + " v.model_version_properties, v.model_version_uri_name, 
v.model_version_uri, v.audit_info, v.deleted_at"
+        + " FROM ("
+        + "<foreach collection='modelVersionMetas' item='version' 
separator='UNION ALL'>"
+        + " SELECT"
+        + " CAST(#{version.modelId} AS BIGINT) AS model_id, 
CAST(#{version.modelVersionComment} AS TEXT) AS model_version_comment,"
+        + " CAST(#{version.modelVersionProperties} AS MEDIUMTEXT) AS 
model_version_properties, CAST(#{version.auditInfo} AS MEDIUMTEXT) AS 
audit_info,"
+        + " CAST(#{version.deletedAt} AS BIGINT) AS deleted_at, 
CAST(#{version.modelVersionUriName} AS VARCHAR(128)) AS model_version_uri_name,"
+        + " CAST(#{version.modelVersionUri} AS TEXT) AS model_version_uri "
+        + "</foreach>"
+        + " ) v"
+        + " JOIN"
+        + " (SELECT metalake_id, catalog_id, schema_id, model_id, 
model_latest_version"
+        + " FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " WHERE model_id = #{modelVersionMetas[0].modelId} AND deleted_at = 
0) m"
+        + " ON v.model_id = m.model_id"
+        + "</script>";
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/po/ModelVersionPO.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/po/ModelVersionPO.java
index 59ca6271ef..0ff700fdc1 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/po/ModelVersionPO.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/po/ModelVersionPO.java
@@ -41,6 +41,8 @@ public class ModelVersionPO {
 
   private String modelVersionProperties;
 
+  private String modelVersionUriName;
+
   private String modelVersionUri;
 
   private String auditInfo;
@@ -96,6 +98,11 @@ public class ModelVersionPO {
       return this;
     }
 
+    public Builder withModelVersionUriName(String modelVersionUriName) {
+      modelVersionPO.modelVersionUriName = modelVersionUriName;
+      return this;
+    }
+
     public Builder withModelVersionUri(String modelVersionUri) {
       modelVersionPO.modelVersionUri = modelVersionUri;
       return this;
@@ -112,6 +119,9 @@ public class ModelVersionPO {
     }
 
     public ModelVersionPO build() {
+      Preconditions.checkArgument(
+          StringUtils.isNotBlank(modelVersionPO.modelVersionUriName),
+          "Model version uri name cannot be empty");
       Preconditions.checkArgument(
           StringUtils.isNotBlank(modelVersionPO.modelVersionUri),
           "Model version uri cannot be empty");
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
index 4cd8a3a7f9..cadd262059 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
@@ -18,12 +18,17 @@
  */
 package org.apache.gravitino.storage.relational.service;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
@@ -36,6 +41,7 @@ import org.apache.gravitino.Namespace;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
 import org.apache.gravitino.meta.ModelEntity;
 import org.apache.gravitino.meta.ModelVersionEntity;
+import org.apache.gravitino.model.ModelVersion;
 import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import 
org.apache.gravitino.storage.relational.mapper.ModelVersionAliasRelMapper;
 import org.apache.gravitino.storage.relational.mapper.ModelVersionMetaMapper;
@@ -46,8 +52,6 @@ import 
org.apache.gravitino.storage.relational.utils.POConverters;
 import org.apache.gravitino.storage.relational.utils.SessionUtils;
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.apache.gravitino.utils.NamespaceUtil;
-import org.glassfish.jersey.internal.guava.Lists;
-import org.glassfish.jersey.internal.guava.Preconditions;
 
 public class ModelVersionMetaService {
 
@@ -84,14 +88,20 @@ public class ModelVersionMetaService {
         ArrayListMultimap.create();
     aliasRelPOs.forEach(r -> 
aliasRelPOsByModelVersion.put(r.getModelVersion(), r));
 
-    return modelVersionPOs.stream()
-        .map(
-            m -> {
-              List<ModelVersionAliasRelPO> versionAliasRelPOs =
-                  
Lists.newArrayList(aliasRelPOsByModelVersion.get(m.getModelVersion()));
-              return POConverters.fromModelVersionPO(modelIdent, m, 
versionAliasRelPOs);
-            })
-        .collect(Collectors.toList());
+    return ImmutableList.copyOf(
+        modelVersionPOs.stream()
+            .collect(
+                Collectors.groupingBy(
+                    ModelVersionPO::getModelVersion,
+                    Collectors.collectingAndThen(
+                        Collectors.<ModelVersionPO>toList(),
+                        m -> {
+                          List<ModelVersionAliasRelPO> versionAliasRelPOs =
+                              Lists.newArrayList(
+                                  
aliasRelPOsByModelVersion.get(m.get(0).getModelVersion()));
+                          return POConverters.fromModelVersionPO(modelIdent, 
m, versionAliasRelPOs);
+                        })))
+            .values());
   }
 
   public ModelVersionEntity getModelVersionByIdentifier(NameIdentifier ident) {
@@ -103,7 +113,7 @@ public class ModelVersionMetaService {
 
     boolean isVersionNumber = NumberUtils.isCreatable(ident.name());
 
-    ModelVersionPO modelVersionPO =
+    List<ModelVersionPO> modelVersionPOs =
         SessionUtils.getWithoutCommit(
             ModelVersionMetaMapper.class,
             mapper -> {
@@ -115,7 +125,7 @@ public class ModelVersionMetaService {
               }
             });
 
-    if (modelVersionPO == null) {
+    if (modelVersionPOs.isEmpty()) {
       throw new NoSuchEntityException(
           NoSuchEntityException.NO_SUCH_ENTITY_MESSAGE,
           Entity.EntityType.MODEL_VERSION.name().toLowerCase(Locale.ROOT),
@@ -135,7 +145,7 @@ public class ModelVersionMetaService {
               }
             });
 
-    return POConverters.fromModelVersionPO(modelIdent, modelVersionPO, 
aliasRelPOs);
+    return POConverters.fromModelVersionPO(modelIdent, modelVersionPOs, 
aliasRelPOs);
   }
 
   public void insertModelVersion(ModelVersionEntity modelVersionEntity) throws 
IOException {
@@ -148,9 +158,8 @@ public class ModelVersionMetaService {
         ModelMetaService.getInstance()
             .getModelIdBySchemaIdAndModelName(schemaId, modelIdent.name());
 
-    ModelVersionPO.Builder builder = 
ModelVersionPO.builder().withModelId(modelId);
-    ModelVersionPO modelVersionPO =
-        POConverters.initializeModelVersionPO(modelVersionEntity, builder);
+    List<ModelVersionPO> modelVersionPOs =
+        POConverters.initializeModelVersionPO(modelVersionEntity, modelId);
     List<ModelVersionAliasRelPO> aliasRelPOs =
         POConverters.initializeModelVersionAliasRelPO(modelVersionEntity, 
modelId);
 
@@ -159,7 +168,7 @@ public class ModelVersionMetaService {
           () ->
               SessionUtils.doWithoutCommit(
                   ModelVersionMetaMapper.class,
-                  mapper -> mapper.insertModelVersionMeta(modelVersionPO)),
+                  mapper -> mapper.insertModelVersionMetas(modelVersionPOs)),
           () -> {
             if (aliasRelPOs.isEmpty()) {
               return;
@@ -269,7 +278,7 @@ public class ModelVersionMetaService {
     boolean isVersionNumber = NumberUtils.isCreatable(ident.name());
     ModelEntity modelEntity = 
ModelMetaService.getInstance().getModelByIdentifier(modelIdent);
 
-    ModelVersionPO oldModelVersionPO =
+    List<ModelVersionPO> oldModelVersionPOs =
         SessionUtils.getWithoutCommit(
             ModelVersionMetaMapper.class,
             mapper -> {
@@ -281,7 +290,7 @@ public class ModelVersionMetaService {
               }
             });
 
-    if (oldModelVersionPO == null) {
+    if (oldModelVersionPOs.isEmpty()) {
       throw new NoSuchEntityException(
           NoSuchEntityException.NO_SUCH_ENTITY_MESSAGE,
           Entity.EntityType.MODEL_VERSION.name().toLowerCase(Locale.ROOT),
@@ -302,7 +311,7 @@ public class ModelVersionMetaService {
             });
 
     ModelVersionEntity oldModelVersionEntity =
-        POConverters.fromModelVersionPO(modelIdent, oldModelVersionPO, 
oldAliasRelPOs);
+        POConverters.fromModelVersionPO(modelIdent, oldModelVersionPOs, 
oldAliasRelPOs);
     ModelVersionEntity newModelVersionEntity =
         (ModelVersionEntity) updater.apply((E) oldModelVersionEntity);
 
@@ -321,26 +330,43 @@ public class ModelVersionMetaService {
     try {
       SessionUtils.doMultipleWithCommit(
           () ->
-              updateResult.set(
+              updateResult.addAndGet(
                   SessionUtils.doWithoutCommitAndFetchResult(
                       ModelVersionMetaMapper.class,
                       mapper ->
                           mapper.updateModelVersionMeta(
                               POConverters.updateModelVersionPO(
-                                  oldModelVersionPO, newModelVersionEntity),
-                              oldModelVersionPO))),
+                                  oldModelVersionPOs.get(0), 
newModelVersionEntity),
+                              oldModelVersionPOs.get(0)))),
+          () ->
+              oldModelVersionPOs.stream()
+                  .filter(v -> isModelVersionUriUpdated(v, 
newModelVersionEntity.uris()))
+                  .findAny()
+                  .ifPresent(
+                      v ->
+                          updateResult.addAndGet(
+                              SessionUtils.doWithoutCommitAndFetchResult(
+                                  ModelVersionMetaMapper.class,
+                                  mapper ->
+                                      mapper.updateModelVersionUris(
+                                          v.getModelId(),
+                                          v.getModelVersion(),
+                                          ImmutableMap.of(
+                                              ModelVersion.URI_NAME_UNKNOWN,
+                                              newModelVersionEntity
+                                                  .uris()
+                                                  
.get(ModelVersion.URI_NAME_UNKNOWN)))))),
           () -> {
             if (isAliasChanged) {
               SessionUtils.doWithoutCommit(
                   ModelVersionAliasRelMapper.class,
-                  mapper -> {
-                    oldModelVersionEntity
-                        .aliases()
-                        .forEach(
-                            alias ->
-                                
mapper.softDeleteModelVersionAliasRelsByModelIdAndAlias(
-                                    modelEntity.id(), alias));
-                  });
+                  mapper ->
+                      oldModelVersionEntity
+                          .aliases()
+                          .forEach(
+                              alias ->
+                                  
mapper.softDeleteModelVersionAliasRelsByModelIdAndAlias(
+                                      modelEntity.id(), alias)));
 
               SessionUtils.doWithoutCommit(
                   ModelVersionAliasRelMapper.class,
@@ -372,4 +398,14 @@ public class ModelVersionMetaService {
 
     return !oldAliases.equals(newAliases);
   }
+
+  // TODO Only modifying the unknown URI is supported currently.
+  private boolean isModelVersionUriUpdated(
+      ModelVersionPO oldModelVersionPO, Map<String, String> 
newModelVersionUris) {
+    return 
ModelVersion.URI_NAME_UNKNOWN.equals(oldModelVersionPO.getModelVersionUriName())
+        && newModelVersionUris.containsKey(ModelVersion.URI_NAME_UNKNOWN)
+        && !oldModelVersionPO
+            .getModelVersionUri()
+            .equals(newModelVersionUris.get(ModelVersion.URI_NAME_UNKNOWN));
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
index 905663ecc5..fc447a06d0 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
@@ -1370,20 +1370,26 @@ public class POConverters {
 
   public static ModelVersionEntity fromModelVersionPO(
       NameIdentifier modelIdent,
-      ModelVersionPO modelVersionPO,
+      List<ModelVersionPO> modelVersionPOs,
       List<ModelVersionAliasRelPO> aliasRelPOs) {
     List<String> aliases =
         aliasRelPOs.stream()
             .map(ModelVersionAliasRelPO::getModelVersionAlias)
             .collect(Collectors.toList());
 
+    Map<String, String> uris =
+        modelVersionPOs.stream()
+            .collect(
+                Collectors.toMap(
+                    ModelVersionPO::getModelVersionUriName, 
ModelVersionPO::getModelVersionUri));
+    ModelVersionPO modelVersionPO = modelVersionPOs.get(0);
     try {
       return ModelVersionEntity.builder()
           .withModelIdentifier(modelIdent)
           .withVersion(modelVersionPO.getModelVersion())
           .withAliases(aliases)
           .withComment(modelVersionPO.getModelVersionComment())
-          .withUri(modelVersionPO.getModelVersionUri())
+          .withUris(uris)
           .withProperties(
               JsonUtils.anyFieldMapper()
                   .readValue(modelVersionPO.getModelVersionProperties(), 
Map.class))
@@ -1439,7 +1445,11 @@ public class POConverters {
           .withMetalakeId(oldModelVersionPO.getMetalakeId())
           .withCatalogId(oldModelVersionPO.getCatalogId())
           .withSchemaId(oldModelVersionPO.getSchemaId())
-          .withModelVersionUri(newModelVersion.uri())
+          // TODO The modelVersionUriName and modelVersionUri here are not 
actually used.
+          // They are only used for occupying positions to avoid verification 
failures. They will
+          // be removed when the model version with multiple URIs is supported 
to be modified later
+          .withModelVersionUriName("uriName")
+          .withModelVersionUri("uri")
           .withModelVersion(oldModelVersionPO.getModelVersion())
           .withModelVersionComment(newModelVersion.comment())
           .withModelVersionProperties(
@@ -1474,21 +1484,30 @@ public class POConverters {
     }
   }
 
-  public static ModelVersionPO initializeModelVersionPO(
-      ModelVersionEntity modelVersionEntity, ModelVersionPO.Builder builder) {
+  public static List<ModelVersionPO> initializeModelVersionPO(
+      ModelVersionEntity modelVersionEntity, Long modelId) {
     try {
-      return builder
-          // Note that version set here will not be used when inserting into 
database, it will
-          // directly use the version from the query to avoid concurrent 
version conflict.
-          .withModelVersion(modelVersionEntity.version())
-          .withModelVersionComment(modelVersionEntity.comment())
-          .withModelVersionUri(modelVersionEntity.uri())
-          .withModelVersionProperties(
-              
JsonUtils.anyFieldMapper().writeValueAsString(modelVersionEntity.properties()))
-          .withAuditInfo(
-              
JsonUtils.anyFieldMapper().writeValueAsString(modelVersionEntity.auditInfo()))
-          .withDeletedAt(DEFAULT_DELETED_AT)
-          .build();
+      String modelVersionProperties =
+          
JsonUtils.anyFieldMapper().writeValueAsString(modelVersionEntity.properties());
+      String modelVersionAuditInfo =
+          
JsonUtils.anyFieldMapper().writeValueAsString(modelVersionEntity.auditInfo());
+      return modelVersionEntity.uris().entrySet().stream()
+          .map(
+              entry ->
+                  ModelVersionPO.builder()
+                      .withModelId(modelId)
+                      // Note that version set here will not be used when 
inserting into database,
+                      // it will directly use the version from the query to 
avoid concurrent version
+                      // conflict.
+                      .withModelVersion(modelVersionEntity.version())
+                      .withModelVersionComment(modelVersionEntity.comment())
+                      .withModelVersionUriName(entry.getKey())
+                      .withModelVersionUri(entry.getValue())
+                      .withModelVersionProperties(modelVersionProperties)
+                      .withAuditInfo(modelVersionAuditInfo)
+                      .withDeletedAt(DEFAULT_DELETED_AT)
+                      .build())
+          .collect(Collectors.toList());
     } catch (JsonProcessingException e) {
       throw new RuntimeException("Failed to serialize json object:", e);
     }
diff --git 
a/core/src/test/java/org/apache/gravitino/cache/TestCaffeineEntityCache.java 
b/core/src/test/java/org/apache/gravitino/cache/TestCaffeineEntityCache.java
index 489c3c044d..2b9e29146e 100644
--- a/core/src/test/java/org/apache/gravitino/cache/TestCaffeineEntityCache.java
+++ b/core/src/test/java/org/apache/gravitino/cache/TestCaffeineEntityCache.java
@@ -47,6 +47,7 @@ import org.apache.gravitino.meta.TableEntity;
 import org.apache.gravitino.meta.TagEntity;
 import org.apache.gravitino.meta.TopicEntity;
 import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.model.ModelVersion;
 import org.apache.gravitino.utils.TestUtil;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -614,7 +615,7 @@ public class TestCaffeineEntityCache {
         TestUtil.getTestModelVersionEntity(
             testModelEntity.nameIdentifier(),
             1,
-            "s3://test/path",
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "s3://test/path"),
             ImmutableMap.of(),
             "test model version",
             ImmutableList.of("alias1", "alias2"));
diff --git 
a/core/src/test/java/org/apache/gravitino/meta/TestModelVersionEntity.java 
b/core/src/test/java/org/apache/gravitino/meta/TestModelVersionEntity.java
index 44ec19ab45..df6aca484e 100644
--- a/core/src/test/java/org/apache/gravitino/meta/TestModelVersionEntity.java
+++ b/core/src/test/java/org/apache/gravitino/meta/TestModelVersionEntity.java
@@ -21,10 +21,12 @@ package org.apache.gravitino.meta;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import java.time.Instant;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
+import org.apache.gravitino.model.ModelVersion;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -44,7 +46,7 @@ public class TestModelVersionEntity {
             .withComment("test comment")
             .withAliases(aliases)
             .withProperties(properties)
-            .withUri("test_uri")
+            .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, 
"test_uri"))
             .withAuditInfo(auditInfo)
             .build();
 
@@ -54,7 +56,10 @@ public class TestModelVersionEntity {
     Assertions.assertEquals("test comment", modelVersionEntity.comment());
     Assertions.assertEquals(aliases, modelVersionEntity.aliases());
     Assertions.assertEquals(properties, modelVersionEntity.properties());
-    Assertions.assertEquals("test_uri", modelVersionEntity.uri());
+    Assertions.assertEquals(1, modelVersionEntity.uris().size());
+    
Assertions.assertTrue(modelVersionEntity.uris().containsKey(ModelVersion.URI_NAME_UNKNOWN));
+    Assertions.assertEquals(
+        "test_uri", 
modelVersionEntity.uris().get(ModelVersion.URI_NAME_UNKNOWN));
     Assertions.assertEquals(auditInfo, modelVersionEntity.auditInfo());
     Assertions.assertEquals(
         Namespace.of("m1", "c1", "s1", "model1"), 
modelVersionEntity.namespace());
@@ -67,7 +72,7 @@ public class TestModelVersionEntity {
             .withVersion(1)
             .withAliases(aliases)
             .withProperties(properties)
-            .withUri("test_uri")
+            .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, 
"test_uri"))
             .withAuditInfo(auditInfo)
             .build();
     Assertions.assertNull(modelVersionEntity2.comment());
@@ -78,7 +83,7 @@ public class TestModelVersionEntity {
             .withVersion(1)
             .withComment("test comment")
             .withAliases(aliases)
-            .withUri("test_uri")
+            .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, 
"test_uri"))
             .withAuditInfo(auditInfo)
             .build();
     Assertions.assertNull(modelVersionEntity3.properties());
@@ -89,7 +94,7 @@ public class TestModelVersionEntity {
             .withVersion(1)
             .withComment("test comment")
             .withProperties(properties)
-            .withUri("test_uri")
+            .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, 
"test_uri"))
             .withAuditInfo(auditInfo)
             .build();
     Assertions.assertTrue(modelVersionEntity4.aliases().isEmpty());
@@ -102,18 +107,26 @@ public class TestModelVersionEntity {
 
     Assertions.assertThrows(
         IllegalArgumentException.class,
-        () -> {
-          ModelVersionEntity.builder()
-              .withVersion(1)
-              .withAuditInfo(
-                  
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
-              .build();
-        });
+        () ->
+            ModelVersionEntity.builder()
+                .withVersion(1)
+                .withAuditInfo(
+                    
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+                .build());
+
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () ->
+            ModelVersionEntity.builder()
+                .withVersion(1)
+                .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, 
"test_uri"))
+                .build());
+
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> 
ModelVersionEntity.builder().withVersion(1).build());
 
     Assertions.assertThrows(
         IllegalArgumentException.class,
-        () -> {
-          
ModelVersionEntity.builder().withVersion(1).withUri("test_uri").build();
-        });
+        () -> 
ModelVersionEntity.builder().withVersion(1).withUris(Collections.emptyMap()).build());
   }
 }
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java 
b/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java
index 69914c91ed..389bb6cfc2 100644
--- a/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java
+++ b/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java
@@ -86,6 +86,7 @@ import org.apache.gravitino.meta.SchemaVersion;
 import org.apache.gravitino.meta.TableEntity;
 import org.apache.gravitino.meta.TopicEntity;
 import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.model.ModelVersion;
 import org.apache.gravitino.rel.types.Type;
 import org.apache.gravitino.rel.types.Types;
 import org.apache.gravitino.storage.relational.RelationalBackend;
@@ -312,7 +313,7 @@ public class TestEntityStorage {
           TestJDBCBackend.createModelVersionEntity(
               model1.nameIdentifier(),
               0,
-              "model_path",
+              ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
               ImmutableList.of("alias1", "alias2"),
               null,
               null,
@@ -705,7 +706,7 @@ public class TestEntityStorage {
           TestJDBCBackend.createModelVersionEntity(
               model1.nameIdentifier(),
               0,
-              "model_path",
+              ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
               ImmutableList.of("alias1", "alias2"),
               null,
               null,
@@ -745,7 +746,7 @@ public class TestEntityStorage {
           TestJDBCBackend.createModelVersionEntity(
               model1InSchema2.nameIdentifier(),
               0,
-              "model_path",
+              ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
               ImmutableList.of("alias1", "alias2"),
               null,
               null,
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
index 0e68c62f1b..7c0169ce6c 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
@@ -1501,7 +1501,7 @@ public class TestJDBCBackend {
   public static ModelVersionEntity createModelVersionEntity(
       NameIdentifier modelId,
       Integer version,
-      String modelUri,
+      Map<String, String> modelUris,
       List<String> aliases,
       String comment,
       Map<String, String> properties,
@@ -1509,7 +1509,7 @@ public class TestJDBCBackend {
     return ModelVersionEntity.builder()
         .withModelIdentifier(modelId)
         .withVersion(version)
-        .withUri(modelUri)
+        .withUris(modelUris)
         .withAliases(aliases)
         .withComment(comment)
         .withProperties(properties)
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
index 06102f6447..b0e2c1a866 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
@@ -36,6 +36,7 @@ import 
org.apache.gravitino.exceptions.NonEmptyEntityException;
 import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.meta.ModelEntity;
 import org.apache.gravitino.meta.ModelVersionEntity;
+import org.apache.gravitino.model.ModelVersion;
 import org.apache.gravitino.storage.RandomIdGenerator;
 import org.apache.gravitino.storage.relational.TestJDBCBackend;
 import org.apache.gravitino.utils.NameIdentifierUtil;
@@ -84,7 +85,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             0,
-            "model_path",
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
             aliases,
             "test comment",
             properties,
@@ -114,7 +115,13 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
     // Test insert again to get a new version number
     ModelVersionEntity modelVersionEntity2 =
         createModelVersionEntity(
-            modelEntity.nameIdentifier(), 1, "model_path", null, null, null, 
auditInfo);
+            modelEntity.nameIdentifier(),
+            1,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
+            null,
+            null,
+            null,
+            auditInfo);
 
     Assertions.assertDoesNotThrow(
         () -> 
ModelVersionMetaService.getInstance().insertModelVersion(modelVersionEntity2));
@@ -179,7 +186,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             NameIdentifier.of(MODEL_NS, "model2"),
             1,
-            "model_path",
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
             aliases,
             "test comment",
             properties,
@@ -213,7 +220,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             0,
-            "model_path",
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
             aliases,
             "test comment",
             properties,
@@ -231,7 +238,13 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
     // Test insert again to get a new version number
     ModelVersionEntity modelVersionEntity2 =
         createModelVersionEntity(
-            modelEntity.nameIdentifier(), 1, "model_path", null, null, null, 
auditInfo);
+            modelEntity.nameIdentifier(),
+            1,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
+            null,
+            null,
+            null,
+            auditInfo);
 
     Assertions.assertDoesNotThrow(
         () -> 
ModelVersionMetaService.getInstance().insertModelVersion(modelVersionEntity2));
@@ -277,7 +290,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             0,
-            "model_path",
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
             aliases,
             "test comment",
             properties,
@@ -324,7 +337,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             1,
-            "model_path",
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
             aliases,
             "test comment",
             properties,
@@ -373,6 +386,101 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
                     getModelVersionIdent(modelEntity.nameIdentifier(), 
"alias2")));
   }
 
+  @Test
+  public void testModelVersionWithMultipleUris() throws IOException {
+    createParentEntities(METALAKE_NAME, CATALOG_NAME, SCHEMA_NAME, auditInfo);
+
+    // Create a model entity
+    ModelEntity modelEntity =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            MODEL_NS,
+            "model1",
+            "model1 comment",
+            0,
+            properties,
+            auditInfo);
+    Assertions.assertDoesNotThrow(
+        () -> ModelMetaService.getInstance().insertModel(modelEntity, false));
+
+    // Create a model version entity with multiple URIs
+    ModelVersionEntity modelVersionEntity =
+        createModelVersionEntity(
+            modelEntity.nameIdentifier(),
+            0,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri1", 
"uri-name-2", "uri2"),
+            aliases,
+            "test comment",
+            properties,
+            auditInfo);
+
+    Assertions.assertDoesNotThrow(
+        () -> 
ModelVersionMetaService.getInstance().insertModelVersion(modelVersionEntity));
+
+    // Test if the model version can be retrieved by the identifier
+    Assertions.assertEquals(
+        modelVersionEntity,
+        ModelVersionMetaService.getInstance()
+            
.getModelVersionByIdentifier(getModelVersionIdent(modelEntity.nameIdentifier(), 
0)));
+
+    Assertions.assertEquals(
+        modelVersionEntity,
+        ModelVersionMetaService.getInstance()
+            .getModelVersionByIdentifier(
+                getModelVersionIdent(modelEntity.nameIdentifier(), "alias1")));
+
+    Assertions.assertEquals(
+        modelVersionEntity,
+        ModelVersionMetaService.getInstance()
+            .getModelVersionByIdentifier(
+                getModelVersionIdent(modelEntity.nameIdentifier(), "alias2")));
+
+    // Test list model versions
+    List<ModelVersionEntity> modelVersions =
+        ModelVersionMetaService.getInstance()
+            
.listModelVersionsByNamespace(getModelVersionNs(modelEntity.nameIdentifier()));
+    Assertions.assertEquals(1, modelVersions.size());
+    Assertions.assertEquals(modelVersionEntity, modelVersions.get(0));
+
+    // Test update model version
+    ModelVersionEntity updatedModelVersionEntity =
+        createModelVersionEntity(
+            modelVersionEntity.modelIdentifier(),
+            modelVersionEntity.version(),
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri1-updated", 
"uri-name-2", "uri2"),
+            ImmutableList.of("alias2", "alias3"),
+            "updated comment",
+            ImmutableMap.of("k1", "v1", "k2", "v2"),
+            modelVersionEntity.auditInfo());
+
+    Function<ModelVersionEntity, ModelVersionEntity> updatePropertiesUpdater =
+        oldModelVersionEntity -> updatedModelVersionEntity;
+
+    ModelVersionEntity alteredModelVersionEntity =
+        ModelVersionMetaService.getInstance()
+            .updateModelVersion(modelVersionEntity.nameIdentifier(), 
updatePropertiesUpdater);
+    Assertions.assertEquals(updatedModelVersionEntity, 
alteredModelVersionEntity);
+
+    // Test if the model version is updated
+    Assertions.assertEquals(
+        updatedModelVersionEntity,
+        ModelVersionMetaService.getInstance()
+            
.getModelVersionByIdentifier(getModelVersionIdent(modelEntity.nameIdentifier(), 
0)));
+
+    // Test delete the model version
+    Assertions.assertTrue(
+        ModelVersionMetaService.getInstance()
+            
.deleteModelVersion(getModelVersionIdent(modelEntity.nameIdentifier(), 0)));
+
+    // Test fetch a non-exist model version
+    Assertions.assertThrows(
+        NoSuchEntityException.class,
+        () ->
+            ModelVersionMetaService.getInstance()
+                .getModelVersionByIdentifier(
+                    getModelVersionIdent(modelEntity.nameIdentifier(), 0)));
+  }
+
   @ParameterizedTest
   @ValueSource(strings = {"model", "schema", "catalog", "metalake"})
   public void testDeleteModelVersionsInDeletion(String input) throws 
IOException {
@@ -397,7 +505,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             0,
-            "model_path",
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
             aliases,
             "test comment",
             properties,
@@ -408,7 +516,13 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
 
     ModelVersionEntity modelVersionEntity1 =
         createModelVersionEntity(
-            modelEntity.nameIdentifier(), 1, "model_path", null, null, null, 
auditInfo);
+            modelEntity.nameIdentifier(),
+            1,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "model_path"),
+            null,
+            null,
+            null,
+            auditInfo);
 
     Assertions.assertDoesNotThrow(
         () -> 
ModelVersionMetaService.getInstance().insertModelVersion(modelVersionEntity1));
@@ -492,7 +606,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             version,
-            modelVersionUri,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, modelVersionUri),
             modelVersionAliases,
             modelVersionComment,
             properties,
@@ -502,7 +616,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelVersionEntity.modelIdentifier(),
             modelVersionEntity.version(),
-            modelVersionEntity.uri(),
+            modelVersionEntity.uris(),
             modelVersionEntity.aliases(),
             updatedComment,
             modelVersionEntity.properties(),
@@ -576,7 +690,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             version,
-            modelVersionUri,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, modelVersionUri),
             modelVersionAliases,
             modelVersionComment,
             properties,
@@ -586,7 +700,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelVersionEntity.modelIdentifier(),
             modelVersionEntity.version(),
-            modelVersionEntity.uri(),
+            modelVersionEntity.uris(),
             modelVersionEntity.aliases(),
             modelVersionEntity.comment(),
             updatedProperties,
@@ -659,7 +773,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             version,
-            modelVersionUri,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, modelVersionUri),
             modelVersionAliases,
             modelVersionComment,
             properties,
@@ -669,7 +783,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelVersionEntity.modelIdentifier(),
             modelVersionEntity.version(),
-            updatedUri,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, updatedUri),
             modelVersionEntity.aliases(),
             modelVersionEntity.comment(),
             modelVersionEntity.properties(),
@@ -742,7 +856,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelEntity.nameIdentifier(),
             version,
-            modelVersionUri,
+            ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, modelVersionUri),
             modelVersionAliases,
             modelVersionComment,
             properties,
@@ -752,7 +866,7 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
         createModelVersionEntity(
             modelVersionEntity.modelIdentifier(),
             modelVersionEntity.version(),
-            modelVersionEntity.uri(),
+            modelVersionEntity.uris(),
             updatedVersionAliases,
             modelVersionEntity.comment(),
             modelVersionEntity.properties(),
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
index 382e5c9b31..858b1a8dd7 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
@@ -1022,39 +1022,33 @@ public class TestPOConverters {
             .withAliases(ImmutableList.of("alias1"))
             .withComment("this is test")
             .withProperties(ImmutableMap.of("key", "value"))
-            .withUri("hdfs://localhost/test")
+            .withUris(ImmutableMap.of("unknown", "hdfs://localhost/test"))
             .withAuditInfo(auditInfo)
             .build();
 
-    ModelVersionPO.Builder builder1 =
-        ModelVersionPO.builder()
-            .withModelId(1L)
-            .withMetalakeId(1L)
-            .withCatalogId(1L)
-            .withSchemaId(1L);
-
-    ModelVersionPO modelVersionPO =
-        POConverters.initializeModelVersionPO(modelVersionEntity, builder1);
-    Assertions.assertEquals(1, modelVersionPO.getModelVersion());
-    Assertions.assertEquals(1L, modelVersionPO.getModelId());
-    Assertions.assertEquals(1L, modelVersionPO.getMetalakeId());
-    Assertions.assertEquals(1L, modelVersionPO.getCatalogId());
-    Assertions.assertEquals(1L, modelVersionPO.getSchemaId());
-    Assertions.assertEquals("this is test", 
modelVersionPO.getModelVersionComment());
-    Assertions.assertEquals("hdfs://localhost/test", 
modelVersionPO.getModelVersionUri());
-    Assertions.assertEquals(0L, modelVersionPO.getDeletedAt());
+    List<ModelVersionPO> modelVersionPOs =
+        POConverters.initializeModelVersionPO(modelVersionEntity, 1L);
+    Assertions.assertEquals(1, modelVersionPOs.size());
+    Assertions.assertEquals(1, modelVersionPOs.get(0).getModelVersion());
+    Assertions.assertEquals(1L, modelVersionPOs.get(0).getModelId());
+    Assertions.assertEquals("this is test", 
modelVersionPOs.get(0).getModelVersionComment());
+    Assertions.assertEquals("unknown", 
modelVersionPOs.get(0).getModelVersionUriName());
+    Assertions.assertEquals("hdfs://localhost/test", 
modelVersionPOs.get(0).getModelVersionUri());
+    Assertions.assertEquals(0L, modelVersionPOs.get(0).getDeletedAt());
 
     Map<String, String> resultProperties =
-        
JsonUtils.anyFieldMapper().readValue(modelVersionPO.getModelVersionProperties(),
 Map.class);
+        JsonUtils.anyFieldMapper()
+            .readValue(modelVersionPOs.get(0).getModelVersionProperties(), 
Map.class);
     Assertions.assertEquals(ImmutableMap.of("key", "value"), resultProperties);
 
     AuditInfo resultAuditInfo =
-        JsonUtils.anyFieldMapper().readValue(modelVersionPO.getAuditInfo(), 
AuditInfo.class);
+        JsonUtils.anyFieldMapper()
+            .readValue(modelVersionPOs.get(0).getAuditInfo(), AuditInfo.class);
     Assertions.assertEquals(auditInfo, resultAuditInfo);
 
     List<ModelVersionAliasRelPO> aliasPOs =
         POConverters.initializeModelVersionAliasRelPO(
-            modelVersionEntity, modelVersionPO.getModelId());
+            modelVersionEntity, modelVersionPOs.get(0).getModelId());
     Assertions.assertEquals(1, aliasPOs.size());
     Assertions.assertEquals(1, aliasPOs.get(0).getModelVersion());
     Assertions.assertEquals("alias1", aliasPOs.get(0).getModelVersionAlias());
@@ -1069,29 +1063,23 @@ public class TestPOConverters {
             .withAliases(null)
             .withComment(null)
             .withProperties(null)
-            .withUri("hdfs://localhost/test")
+            .withUris(ImmutableMap.of("unknown", "hdfs://localhost/test"))
             .withAuditInfo(auditInfo)
             .build();
 
-    ModelVersionPO.Builder builder2 =
-        ModelVersionPO.builder()
-            .withModelId(1L)
-            .withMetalakeId(1L)
-            .withCatalogId(1L)
-            .withSchemaId(1L);
-
-    ModelVersionPO modelVersionPOWithNull =
-        POConverters.initializeModelVersionPO(modelVersionEntityWithNull, 
builder2);
-    Assertions.assertNull(modelVersionPOWithNull.getModelVersionComment());
+    List<ModelVersionPO> modelVersionPOsWithNull =
+        POConverters.initializeModelVersionPO(modelVersionEntityWithNull, 1L);
+    Assertions.assertEquals(1, modelVersionPOsWithNull.size());
+    
Assertions.assertNull(modelVersionPOsWithNull.get(0).getModelVersionComment());
 
     Map<String, String> resultPropertiesWithNull =
         JsonUtils.anyFieldMapper()
-            .readValue(modelVersionPOWithNull.getModelVersionProperties(), 
Map.class);
+            
.readValue(modelVersionPOsWithNull.get(0).getModelVersionProperties(), 
Map.class);
     Assertions.assertNull(resultPropertiesWithNull);
 
     List<ModelVersionAliasRelPO> aliasPOsWithNull =
         POConverters.initializeModelVersionAliasRelPO(
-            modelVersionEntityWithNull, modelVersionPOWithNull.getModelId());
+            modelVersionEntityWithNull, 
modelVersionPOsWithNull.get(0).getModelId());
     Assertions.assertEquals(0, aliasPOsWithNull.size());
   }
 
@@ -1113,6 +1101,7 @@ public class TestPOConverters {
             .withModelVersionComment("this is test")
             
.withModelVersionProperties(JsonUtils.anyFieldMapper().writeValueAsString(properties))
             
.withAuditInfo(JsonUtils.anyFieldMapper().writeValueAsString(auditInfo))
+            .withModelVersionUriName("unknown")
             .withModelVersionUri("hdfs://localhost/test")
             .withDeletedAt(0L)
             .build();
@@ -1135,12 +1124,12 @@ public class TestPOConverters {
             .withAliases(aliases)
             .withComment("this is test")
             .withProperties(properties)
-            .withUri("hdfs://localhost/test")
+            .withUris(ImmutableMap.of("unknown", "hdfs://localhost/test"))
             .withAuditInfo(auditInfo)
             .build();
 
     ModelVersionEntity convertedModelVersion =
-        POConverters.fromModelVersionPO(modelIdent, modelVersionPO, aliasPOs);
+        POConverters.fromModelVersionPO(modelIdent, 
ImmutableList.of(modelVersionPO), aliasPOs);
     assertEquals(expectedModelVersion, convertedModelVersion);
 
     // test null fields
@@ -1154,6 +1143,7 @@ public class TestPOConverters {
             .withModelVersionComment(null)
             
.withModelVersionProperties(JsonUtils.anyFieldMapper().writeValueAsString(null))
             
.withAuditInfo(JsonUtils.anyFieldMapper().writeValueAsString(auditInfo))
+            .withModelVersionUriName("unknown")
             .withModelVersionUri("hdfs://localhost/test")
             .withDeletedAt(0L)
             .build();
@@ -1166,12 +1156,13 @@ public class TestPOConverters {
             .withAliases(Collections.emptyList())
             .withComment(null)
             .withProperties(null)
-            .withUri("hdfs://localhost/test")
+            .withUris(ImmutableMap.of("unknown", "hdfs://localhost/test"))
             .withAuditInfo(auditInfo)
             .build();
 
     ModelVersionEntity convertedModelVersionWithNull =
-        POConverters.fromModelVersionPO(modelIdent, modelVersionPOWithNull, 
aliasPOsWithNull);
+        POConverters.fromModelVersionPO(
+            modelIdent, ImmutableList.of(modelVersionPOWithNull), 
aliasPOsWithNull);
     assertEquals(expectedModelVersionWithNull, convertedModelVersionWithNull);
   }
 
diff --git a/core/src/test/java/org/apache/gravitino/utils/TestUtil.java 
b/core/src/test/java/org/apache/gravitino/utils/TestUtil.java
index 4c6beb2a99..1242a342ed 100644
--- a/core/src/test/java/org/apache/gravitino/utils/TestUtil.java
+++ b/core/src/test/java/org/apache/gravitino/utils/TestUtil.java
@@ -48,6 +48,7 @@ import org.apache.gravitino.meta.TableEntity;
 import org.apache.gravitino.meta.TagEntity;
 import org.apache.gravitino.meta.TopicEntity;
 import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.model.ModelVersion;
 import org.apache.gravitino.rel.types.Types;
 import org.apache.gravitino.storage.RandomIdGenerator;
 
@@ -464,7 +465,7 @@ public class TestUtil {
     return getTestModelVersionEntity(
         NameIdentifier.of("m1", "c1", "s1", "model-version-test"),
         1,
-        "uri",
+        ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri"),
         ImmutableMap.of("key1", "value1"),
         "model version entity test",
         ImmutableList.of("alias1", "alias2"));
@@ -476,7 +477,7 @@ public class TestUtil {
    *
    * @param modelIdentifier The model identifier of the model version entity.
    * @param version The version of the model version entity.
-   * @param uri The uri of the model version entity.
+   * @param uris The uri and their names of the model version entity.
    * @param properties The properties of the model version entity.
    * @param comment The comment of the model version entity.
    * @param aliases The aliases of the model version entity.
@@ -485,14 +486,14 @@ public class TestUtil {
   public static ModelVersionEntity getTestModelVersionEntity(
       NameIdentifier modelIdentifier,
       int version,
-      String uri,
+      Map<String, String> uris,
       Map<String, String> properties,
       String comment,
       List<String> aliases) {
     return ModelVersionEntity.builder()
         .withVersion(version)
         .withModelIdentifier(modelIdentifier)
-        .withUri(uri)
+        .withUris(uris)
         .withProperties(properties)
         .withComment(comment)
         .withAuditInfo(getTestAuditInfo())
diff --git a/scripts/h2/schema-1.0.0-h2.sql b/scripts/h2/schema-1.0.0-h2.sql
index 9231006253..a02f0eb427 100644
--- a/scripts/h2/schema-1.0.0-h2.sql
+++ b/scripts/h2/schema-1.0.0-h2.sql
@@ -317,11 +317,12 @@ CREATE TABLE IF NOT EXISTS `model_version_info` (
     `version` INT UNSIGNED NOT NULL COMMENT 'model version',
     `model_version_comment` TEXT DEFAULT NULL COMMENT 'model version comment',
     `model_version_properties` MEDIUMTEXT DEFAULT NULL COMMENT 'model version 
properties',
+    `model_version_uri_name` VARCHAR(128) NOT NULL COMMENT 'model version uri 
name',
     `model_version_uri` TEXT NOT NULL COMMENT 'model storage uri',
     `audit_info` MEDIUMTEXT NOT NULL COMMENT 'model version audit info',
     `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'model version 
deleted at',
     PRIMARY KEY (`id`),
-    UNIQUE KEY `uk_mid_ver_del` (`model_id`, `version`, `deleted_at`),
+    UNIQUE KEY `uk_mid_ver_uri_del` (`model_id`, `version`, 
`model_version_uri_name`, `deleted_at`),
     KEY `idx_vmid` (`metalake_id`),
     KEY `idx_vcid` (`catalog_id`),
     KEY `idx_vsid` (`schema_id`)
diff --git a/scripts/h2/upgrade-0.9.0-to-1.0.0-h2.sql 
b/scripts/h2/upgrade-0.9.0-to-1.0.0-h2.sql
index 44878633b2..f156d49551 100644
--- a/scripts/h2/upgrade-0.9.0-to-1.0.0-h2.sql
+++ b/scripts/h2/upgrade-0.9.0-to-1.0.0-h2.sql
@@ -60,4 +60,11 @@ CREATE TABLE IF NOT EXISTS `policy_relation_meta` (
     UNIQUE KEY `uk_pi_mi_mo_del` (`policy_id`, `metadata_object_id`, 
`metadata_object_type`, `deleted_at`),
     KEY `idx_pid` (`policy_id`),
     KEY `idx_mid` (`metadata_object_id`)
-) ENGINE=InnoDB;
\ No newline at end of file
+) ENGINE=InnoDB;
+
+-- using default 'unknown' to fill in the new column for compatibility
+ALTER TABLE `model_version_info` ADD COLUMN `model_version_uri_name` 
VARCHAR(256) NOT NULL DEFAULT 'unknown' COMMENT 'model version uri name';
+ALTER TABLE `model_version_info` DROP INDEX `uk_mid_ver_del`;
+ALTER TABLE `model_version_info` ADD CONSTRAINT `uk_mid_ver_uri_del` UNIQUE 
(`model_id`, `version`, `model_version_uri_name`, `deleted_at`);
+-- remove the default value for model_version_uri_name
+ALTER TABLE `model_version_info` ALTER COLUMN `model_version_uri_name` DROP 
DEFAULT;
\ No newline at end of file
diff --git a/scripts/mysql/schema-1.0.0-mysql.sql 
b/scripts/mysql/schema-1.0.0-mysql.sql
index 4f87fe357f..b11c729432 100644
--- a/scripts/mysql/schema-1.0.0-mysql.sql
+++ b/scripts/mysql/schema-1.0.0-mysql.sql
@@ -308,11 +308,12 @@ CREATE TABLE IF NOT EXISTS `model_version_info` (
     `version` INT UNSIGNED NOT NULL COMMENT 'model version',
     `model_version_comment` TEXT DEFAULT NULL COMMENT 'model version comment',
     `model_version_properties` MEDIUMTEXT DEFAULT NULL COMMENT 'model version 
properties',
+    `model_version_uri_name` VARCHAR(256) NOT NULL COMMENT 'model version uri 
name',
     `model_version_uri` TEXT NOT NULL COMMENT 'model storage uri',
     `audit_info` MEDIUMTEXT NOT NULL COMMENT 'model version audit info',
     `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'model version 
deleted at',
     PRIMARY KEY (`id`),
-    UNIQUE KEY `uk_mid_ver_del` (`model_id`, `version`, `deleted_at`),
+    UNIQUE KEY `uk_mid_ver_uri_del` (`model_id`, `version`, 
`model_version_uri_name`, `deleted_at`),
     KEY `idx_mid` (`metalake_id`),
     KEY `idx_cid` (`catalog_id`),
     KEY `idx_sid` (`schema_id`)
diff --git a/scripts/mysql/upgrade-0.9.0-to-1.0.0-mysql.sql 
b/scripts/mysql/upgrade-0.9.0-to-1.0.0-mysql.sql
index 54d54cd789..48438ddfbe 100644
--- a/scripts/mysql/upgrade-0.9.0-to-1.0.0-mysql.sql
+++ b/scripts/mysql/upgrade-0.9.0-to-1.0.0-mysql.sql
@@ -61,3 +61,10 @@ CREATE TABLE IF NOT EXISTS `policy_relation_meta` (
     KEY `idx_pid` (`policy_id`),
     KEY `idx_mid` (`metadata_object_id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT 'policy 
metadata object relation';
+
+-- using default 'unknown' to fill in the new column for compatibility
+ALTER TABLE `model_version_info` ADD COLUMN `model_version_uri_name` 
VARCHAR(256) NOT NULL DEFAULT 'unknown' COMMENT 'model version uri name' AFTER 
`model_version_properties`;
+ALTER TABLE `model_version_info` DROP INDEX `uk_mid_ver_del`;
+ALTER TABLE `model_version_info` ADD CONSTRAINT `uk_mid_ver_uri_del` UNIQUE 
KEY (`model_id`, `version`, `model_version_uri_name`, `deleted_at`);
+-- remove the default value for model_version_uri_name
+ALTER TABLE `model_version_info` ALTER COLUMN `model_version_uri_name` DROP 
DEFAULT;
diff --git a/scripts/postgresql/schema-1.0.0-postgresql.sql 
b/scripts/postgresql/schema-1.0.0-postgresql.sql
index 532f17cc70..7c8ee084fa 100644
--- a/scripts/postgresql/schema-1.0.0-postgresql.sql
+++ b/scripts/postgresql/schema-1.0.0-postgresql.sql
@@ -542,11 +542,12 @@ CREATE TABLE IF NOT EXISTS model_version_info (
     version INT NOT NULL,
     model_version_comment VARCHAR(65535) DEFAULT NULL,
     model_version_properties TEXT DEFAULT NULL,
+    model_version_uri_name VARCHAR(256) NOT NULL,
     model_version_uri TEXT NOT NULL,
     audit_info TEXT NOT NULL,
     deleted_at BIGINT NOT NULL DEFAULT 0,
     PRIMARY KEY (id),
-    UNIQUE (model_id, version, deleted_at)
+    UNIQUE (model_id, version, model_version_uri_name, deleted_at)
     );
 
 CREATE INDEX IF NOT EXISTS idx_metalake_id ON model_version_info (metalake_id);
@@ -562,6 +563,7 @@ COMMENT ON COLUMN model_version_info.model_id IS 'model id';
 COMMENT ON COLUMN model_version_info.version IS 'model version';
 COMMENT ON COLUMN model_version_info.model_version_comment IS 'model version 
comment';
 COMMENT ON COLUMN model_version_info.model_version_properties IS 'model 
version properties';
+COMMENT ON COLUMN model_version_info.model_version_uri_name IS 'model version 
uri name';
 COMMENT ON COLUMN model_version_info.model_version_uri IS 'model storage uri';
 COMMENT ON COLUMN model_version_info.audit_info IS 'model version audit info';
 COMMENT ON COLUMN model_version_info.deleted_at IS 'model version deleted at';
diff --git a/scripts/postgresql/upgrade-0.9.0-to-1.0.0-postgresql.sql 
b/scripts/postgresql/upgrade-0.9.0-to-1.0.0-postgresql.sql
index b01c87a2c6..e96d1a82ae 100644
--- a/scripts/postgresql/upgrade-0.9.0-to-1.0.0-postgresql.sql
+++ b/scripts/postgresql/upgrade-0.9.0-to-1.0.0-postgresql.sql
@@ -96,3 +96,11 @@ COMMENT ON COLUMN policy_relation_meta.audit_info IS 'policy 
relation audit info
 COMMENT ON COLUMN policy_relation_meta.current_version IS 'policy relation 
current version';
 COMMENT ON COLUMN policy_relation_meta.last_version IS 'policy relation last 
version';
 COMMENT ON COLUMN policy_relation_meta.deleted_at IS 'policy relation deleted 
at';
+
+-- using default 'unknown' to fill in the new column for compatibility
+ALTER TABLE model_version_info ADD COLUMN model_version_uri_name VARCHAR(256) 
NOT NULL DEFAULT 'unknown';
+COMMENT ON COLUMN model_version_info.model_version_uri_name IS 'model version 
uri name';
+ALTER TABLE model_version_info DROP CONSTRAINT 
model_version_info_model_id_version_deleted_at_key;
+ALTER TABLE model_version_info ADD CONSTRAINT uk_mid_ver_uri_del UNIQUE 
(model_id, version, model_version_uri_name, deleted_at);
+-- remove the default value for model_version_uri_name
+ALTER TABLE model_version_info ALTER COLUMN model_version_uri_name DROP 
DEFAULT;

Reply via email to