MongoDB复合密钥:InvalidOperationException:{document}.不支持身份 [英] MongoDB Composite Key: InvalidOperationException: {document}.Identity is not supported
问题描述
我在给由复合ID组成的类补水时遇到了问题,而复合ID又具有基类,我在说InvalidOperationException: {document}.Identity is not supported.
I am having issues with hydrating a class which consists of a composite ID which in turn has a base class, I am getting an error saying InvalidOperationException: {document}.Identity is not supported.
我要写入数据库的类如下:
The class i am trying to write to the database is below:
public class Product : IEntity<Product>
{
public readonly Sku Sku;
public string Name { get; private set; }
public string Description { get; private set; }
public bool IsArchived { get; private set; }
public Identity<Product> Identity => Sku;
public Product(Sku sku, string name, bool isArchived)
{
Sku = sku;
Name = name;
IsArchived = isArchived;
}
}
public interface IEntity<T>
{
Identity<T> Identity { get; }
}
依次具有一个ID Sku
,它是由以下复合值(VendorId
和Sku
中的局部Value
)组成的类:
In turn has an ID Sku
which is a class formed of the below composite values (VendorId
and a local Value
within Sku
):
public class Sku : Identity<Product>
{
public readonly VendorId VendorId;
public readonly string Value;
public Sku(VendorId vendorId, string value)
{
VendorId = vendorId;
Value = value;
}
protected override IEnumerable<object> GetIdentityComponents()
{
return new object[] {VendorId, Value};
}
}
public class VendorId : Identity<Vendor>
{
public readonly string Value;
public VendorId(string value)
{
Value = value;
}
protected override IEnumerable<object> GetIdentityComponents()
{
return new object[] {Value};
}
}
我在我的DDD库中使用了实体Identity
的基类,如果可以简化操作的话,本质上,此处的ToString()输出可以用作ID:
I have a base class for my entities Identity
which i use in my DDD libraries, essentially the ToString() output here could be used as the ID if this would simplify things:
public abstract class Identity<T> : IEquatable<Identity<T>>
{
public override bool Equals(object obj) { /* snip */ }
public bool Equals(Identity<T> other) { /* snip */ }
public override int GetHashCode() { /* snip */ }
public override string ToString()
{
var id = string.Empty;
foreach (var component in GetIdentityComponents())
{
if (string.IsNullOrEmpty(id))
id = component.ToString(); // first item, dont add a divider
else
id += "." + component;
}
return id;
}
protected abstract IEnumerable<object> GetIdentityComponents();
}
我在应用启动时注册了映射:
I register the mappings on app start:
// rehydrate readonly properties via matched constructor
// https://stackoverflow.com/questions/39604820/serialize-get-only-properties-on-mongodb
ConventionRegistry
.Register(nameof(ImmutablePocoConvention), new ConventionPack { new ImmutablePocoConvention() }, _ => true);
BsonClassMap.RegisterClassMap<Product>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Sku);
});
BsonClassMap.RegisterClassMap<Vendor>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id);
});
但是当我去写作时,我会得到InvalidOperationException: {document}.Identity is not supported.
However when i go and write, i get InvalidOperationException: {document}.Identity is not supported.
// my respositoru method
public void Upsert<T>(T entity) where T : IEntity<T>
{
this.Database
.GetCollection<T>(product.GetType().FullName)()
.ReplaceOneAsync(x=>x.Identity.Equals(entity.Identity), entity, new UpdateOptions() {IsUpsert = true})
.Wait();
}
var product = new Product(new Sku(new VendorId("dell"), "12434" ),"RAM", false );
myProductRepo.Upsert(product);
不确定我是否直接从我的实体层继续保留(或者我只是使用自动映射器和更简单的POCO)还是现在太复杂了?或者我是否缺少某些映射指令.
Not sure if this is now overly complicated by me persisting direct from my entities layer (or if i just use an automapper and simpler POCO)... or if I am missing some mapping directives.
感谢所有帮助或指示.
推荐答案
我正在通过构造函数发布查看水化作用,该过程是通过GetProperties
完成的.
I was looking at the hydration via constructor post which is done through GetProperties
.
因此public readonly Sku Sku;
不会通过classMap.ClassType.GetTypeInfo().GetProperties(_bindingFlags)
出现,因为它只能作为成员字段进行访问.
So public readonly Sku Sku;
doesn't show up through classMap.ClassType.GetTypeInfo().GetProperties(_bindingFlags)
because it is only can be accessed as member field.
您可以将其更改为public Sku Sku { get; }
,以便通过GetProperties
通过构造函数将其水合,并将所有只读字段(Sku - VendorId, Value
和VendorId - Value
字段)更改为具有属性getter方法.
You can change it to public Sku Sku { get; }
so it is hydrated through constructor via GetProperties
and change all the readonly fields (Sku - VendorId, Value
& VendorId - Value
fields) to have property getter method.
此外,您还必须添加cm.MapProperty(c => c.Identity)
,以便x=>x.Identity.Equals(entity.Identity)
在用作表达式时可以序列化,因为Identity
不能通过ImmutablePocoConvention
进行水合和注册,因为当自动映射逻辑运行时它不是构造函数arg.
Also, You've to add cm.MapProperty(c => c.Identity)
so x=>x.Identity.Equals(entity.Identity)
can be serialized when used as expression because Identity
cannot be hydrated and registered through ImmutablePocoConvention
as it is not a constructor arg when automap logic runs.
代码更改:
public class Sku : Identity<Product>
{
public VendorId VendorId { get; }
public string Value { get; }
}
public class VendorId : Identity<Vendor>
{
public string Value { get; }
}
BsonClassMap.RegisterClassMap<Product>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Sku);
cm.MapProperty(c => c.Identity);
});
这篇关于MongoDB复合密钥:InvalidOperationException:{document}.不支持身份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!