无法使用 marten 和 Linq 查询子类型

如何解决无法使用 marten 和 Linq 查询子类型

我是 marten 的新手,对于应该很简单的查询遇到了严重的困难。我有一个 Person 类,它有一个类型为 EmailAddress 的属性。我想找到任何拥有特定电子邮件地址的人。

public class EmailAddress : ValueObject
{
    // construction
    protected EmailAddress() { } // needed for deserialization

    public EmailAddress(EmailType type,string emailAddress)
    {
        Guard.Against.Null(type,nameof(type));
        Guard.Against.NullOrWhiteSpace(emailAddress,nameof(emailAddress));
        Guard.Against.NotValidEmail(emailAddress,nameof(emailAddress));

        if (!(type.HasFlag(EmailType.Personal) || type.HasFlag(EmailType.Work) || type.HasFlag(EmailType.Other))) throw new ArgumentException("Unable to craete an EmailAddress without a valid type (i.e.,Personal,Work,Other).");

        Type = type;
        Address = emailAddress;
    }


    // properties
    public EmailType Type { get; private set; }
    public string Address { get; private set; }       
}


public class Person : ValueObject
{
    // fields
    List<EmailAddress> _emails = new List<EmailAddress>();

    // Construction
    protected Person() { } // needed for deserialization

    public Person(Guid id,string firstName,string lastName,EmailAddress identityAddress)
    {
        Guard.Against.Default(id,nameof(id));
        Guard.Against.NullOrWhiteSpace(firstName,nameof(firstName));
        Guard.Against.NullOrWhiteSpace(lastName,nameof(lastName));
        Guard.Against.Null(identityAddress,nameof(identityAddress));

        if (!identityAddress.Type.HasFlag(EmailType.IsIdentity))
        {
            identityAddress = new EmailAddress(identityAddress.Type | EmailType.IsIdentity,identityAddress.Address);
        }

        this.Id = id;
        this.FirstName = firstName;
        this.LastName = lastName;
        _emails.Add(identityAddress);
    }

    // properties        
    public Guid Id { get; private set; }
    public string FirstName { get; private set; }
    public string LastName { get; private set; }
    public IReadOnlyList<EmailAddress> Emails { get => _emails; }       
}

我创建了一个连接到 Postgresql 的测试类,并且能够使用 marten 插入类型。序列化器运行良好,能够使用它们的非公共 setter 序列化和反序列化这些类型。但是任何与 Person 类型的 Emails 属性相关的查询都会失败。

    [TestMethod]
    public void Can_Find_Person_Manual()
    {
        // set the test values
        Guid lukeId = Guid.NewGuid();
        EmailAddress lukeEmail = new EmailAddress(EmailType.Work | EmailType.IsIdentity,"luke@skywalkerranch.com");
        Person lukeSkywalker = new Person(lukeId,"Luke","Skywalker",lukeEmail);

        Guid leiaId = Guid.NewGuid();
        EmailAddress leiaEmail = new EmailAddress(EmailType.Personal | EmailType.IsIdentity,"leia@skywalkerranch.com");
        Person leiaSolo = new Person(leiaId,"Leia","Solo",leiaEmail);

        // add a test object
        IDocumentStore database = _container.GetInstance<IDocumentStore>();
        using (var session = database.LightweightSession())
        {
            // clear prior people
            session.DeleteWhere<Person>(p => true);
            session.SaveChanges();

            // Add new people
            session.Store<Person>(lukeSkywalker);
            session.Store<Person>(leiaSolo);
            session.SaveChanges();

            // Start Testing
            IReadOnlyList<Person> people = session.LoadMany<Person>(new Guid[] { lukeId,leiaId });
            Assert.IsTrue(people.Count == 2);

            Person luke = session.Load<Person>(lukeId);
            Assert.IsTrue(luke.Id == lukeId);
            Assert.IsTrue(luke.Emails.Contains(e => e.Address == "luke@skywalkerranch.com"));

            Person foundLuke = session.Query<Person>().Where(p => p.FirstName == "Luke").First();
            Assert.IsTrue(foundLuke.Id == lukeId);

            Person leia = session.Load<Person>(leiaId);
            Assert.IsTrue(leia.Id == leiaId);
            Assert.IsTrue(leia.Emails.Contains(e => e.Address == "leia@skywalkerranch.com"));


            List<Person> allPeople = session.Query<Person>().ToList(); // works fine 2 items

            List<Person> allLeias = session.Query<Person>().Where(p => p.FirstName == "Leia").ToList();  // works fine 1 item

            List<Person> allBills = session.Query<Person>().Where(p => p.FirstName == "Bill").ToList();  // works fine 0 items

            // List<Person> withEmail = session.Query<Person>().Where(p => p.Emails.Count > 0).ToList(); // ERROR returns empty list

            // List<Person> withEmail = session.Query<Person>().Where(p => p.Emails.Count(e => true) > 0).ToList(); // ERROR: select d.data,d.id,d.mt_version from public.mt_doc_person as d where jsonb_array_length(CAST(d.data ->> 'Emails' as jsonb)) > :arg0$ $ 22023: cannot get array length of a non - array' 

            List<Person> allLukes = session.Query<Person>().Where(p => p.Emails.Any(e => e.Address == "luke@skywalkerranch.com")).ToList();  // ERROR NullreferenceException

            //// should get Leia
            List<Person> withPersonalEmail = session.Query<Person>().Where(p => p.Emails.Any(e => e.Type == EmailType.Personal)).ToList(); // ERROR returns empty List

            List<Person> ranchEmail = session.Query<Person>().Where(p => p.Emails.Any(e => e.Address.Contains("ranch"))).ToList();  // ERROR 'Specific method not supported'

            // Below  is the one is need
            Person foundLeia = session.Query<Person>().Where(p => p.Emails.Any(_ => _.Address == "leia@skywalkerranch.com")).SingleOrDefault(); // ERROR returns null
            Assert.IsTrue(foundLeia.Id == leiaId);
        }
    }

解决方法

在我们的例子中,问题是我们的集合属性没有被序列化为 JSON 数组。

我们通过将 Json 序列化器的 CollectionStorage 属性设置为 CollectionStorage.AsArray,因此集合被序列化为 JSON 数组。

请参阅以下链接中的“集合存储”部分:https://martendb.io/documentation/documents/json/newtonsoft/

我们还需要将 TypeNameHandling 设置为 None,以防止在我们的集合被序列化并保存到数据库时存储类型元数据。 (有关详细信息,请参阅上述链接的介绍部分。)

var serialiser = new JsonNetSerializer
{
    CollectionStorage = CollectionStorage.AsArray,EnumStorage = EnumStorage.AsString
};

serialiser.Customize(x =>
{
    x.TypeNameHandling = TypeNameHandling.None;
});

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?