g18*_*18c 5 c# mongodb composite-primary-key
我遇到了保护一个类的问题,该类由一个复合ID组成,而该复合ID又有一个基类,我收到一个错误说法 InvalidOperationException: {document}.Identity is not supported.
我试图写入数据库的类如下:
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; }
}
Run Code Online (Sandbox Code Playgroud)
反过来有一个ID Sku,它是由下面的复合值(VendorId和一个本地Value内部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};
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个我的实体的基类,我Identity在我的DDD库中使用,基本上这里的ToString()输出可以用作ID,如果这会简化事情:
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();
}
Run Code Online (Sandbox Code Playgroud)
我在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);
});
Run Code Online (Sandbox Code Playgroud)
但是,当我去写,我得到 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);
Run Code Online (Sandbox Code Playgroud)
不确定这是否因为我直接从我的实体层持续存在而过于复杂(或者如果我只使用自动化器和更简单的POCO)......或者如果我缺少一些映射指令.
感谢任何帮助或指针.
我正在通过构造函数查看水合作用,这是通过GetProperties.
所以public readonly Sku Sku;不会显示出来,classMap.ClassType.GetTypeInfo().GetProperties(_bindingFlags)因为它只能作为成员字段访问。
您可以将其更改为public Sku Sku { get; }通过构造函数进行水合GetProperties,并将所有只读字段(Sku - VendorId, Value&VendorId - Value字段)更改为具有属性 getter 方法。
另外,您还必须添加cm.MapProperty(c => c.Identity)sox=>x.Identity.Equals(entity.Identity)用作表达式时可以序列化,因为在自动映射逻辑运行时它不是构造函数参数,因此Identity无法水合和注册。ImmutablePocoConvention
代码更改:
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);
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1158 次 |
| 最近记录: |