MongoDB复合密钥:InvalidOperationException:{document}.不支持身份 [英] MongoDB Composite Key: InvalidOperationException: {document}.Identity is not supported

查看:76
本文介绍了MongoDB复合密钥:InvalidOperationException:{document}.不支持身份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在给由复合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,它是由以下复合值(VendorIdSku中的局部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, ValueVendorId - 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 ImmutablePocoConventionas 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆