Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<MinMutationScore>75</MinMutationScore>
<Workstream>AI</Workstream>
<NoWarn>$(NoWarn);S125;S1135;S2302</NoWarn>
<!-- net462 is a fully supported TFM for this package (with dedicated lib/net462 assemblies), so disable the
NETStandardCompatError warning that would incorrectly tell consumers net462 is unsupported. -->
<DisableMinimumSupportedTfmCompatErrors>true</DisableMinimumSupportedTfmCompatErrors>
<PackageProjectUrl>https://learn.microsoft.com/dotnet/ai/vector-stores/overview</PackageProjectUrl>
<PackageTags>vector, database, similarity, ai, query</PackageTags>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ protected virtual void ProcessProperty(PropertyInfo? clrProperty, VectorStorePro
throw new UnreachableException();
}

if (clrProperty is not null)
{
property.PropertyInfo = clrProperty;
}

// Apply storage name: attribute first, then definition (which takes precedence).
SetPropertyStorageName(property, attributeStorageName);
if (definitionProperty is not null)
Expand All @@ -330,11 +335,6 @@ protected virtual void ProcessProperty(PropertyInfo? clrProperty, VectorStorePro
property.ProviderAnnotations = new Dictionary<string, object?>(definitionProperty.ProviderAnnotations);
}

if (clrProperty is not null)
{
property.PropertyInfo = clrProperty;
}

PropertyMap.Add(propertyName, property);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,56 @@ public void IsAutoGenerated_omitted_falls_back_to_SupportsKeyAutoGeneration_fals
Assert.False(model.KeyProperty.IsAutoGenerated);
}

[Fact]
public void StorageName_from_attribute_is_ignored_when_UsesExternalSerializer()
{
// When UsesExternalSerializer is true, the provider uses an external serializer (e.g. System.Text.Json, BSON)
// to determine storage names. Attribute-specified StorageName should be ignored to stay in sync with the serializer.
var builder = new CustomModelBuilder(new CollectionModelBuildingOptions
{
SupportsMultipleVectors = true,
RequiresAtLeastOneVector = false,
UsesExternalSerializer = true
});

var model = builder.Build(typeof(RecordWithStorageNames), typeof(int), definition: null, defaultEmbeddingGenerator: null);

// StorageName should be the CLR property name, NOT the attribute-specified name
Assert.Equal("Id", model.KeyProperty.StorageName);
Assert.Equal("Name", model.DataProperties[0].StorageName);
Assert.Equal("Embedding", model.VectorProperty.StorageName);
}

[Fact]
public void StorageName_from_attribute_is_applied_when_not_UsesExternalSerializer()
{
var builder = new CustomModelBuilder(new CollectionModelBuildingOptions
{
SupportsMultipleVectors = true,
RequiresAtLeastOneVector = false,
UsesExternalSerializer = false
});

var model = builder.Build(typeof(RecordWithStorageNames), typeof(int), definition: null, defaultEmbeddingGenerator: null);

// StorageName should be the attribute-specified name
Assert.Equal("id", model.KeyProperty.StorageName);
Assert.Equal("name", model.DataProperties[0].StorageName);
Assert.Equal("embedding", model.VectorProperty.StorageName);
}

public class RecordWithStorageNames
{
[VectorStoreKey(StorageName = "id")]
public int Id { get; set; }

[VectorStoreData(StorageName = "name")]
public required string Name { get; set; }

[VectorStoreVector(3, StorageName = "embedding")]
public ReadOnlyMemory<float> Embedding { get; set; }
}

public class RecordWithGuidKeyAutoGeneratedTrue
{
[VectorStoreKey(IsAutoGenerated = true)]
Expand Down
Loading